home *** CD-ROM | disk | FTP | other *** search
/ Enter 2001 August / EnterCD8.iso / Internet / HTTrack Website Copier / httrack.exe / {app} / src / htslib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-03  |  84.7 KB  |  3,175 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Fichier librairie .c
  38.  
  39. #include "htslib.h"
  40. #include "htsbauth.h"
  41.  
  42. /* specific definitions */
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsbauth.h"
  46. #include "htsthread.h"
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <time.h>
  51. #include <sys/timeb.h>
  52. #include <fcntl.h>
  53. // pour utimbuf
  54. #if HTS_WIN
  55. #include <sys/utime.h>
  56. #else
  57. #if HTS_PLATFORM!=3
  58. #include <utime.h>
  59. #else
  60. #include <utime.h>
  61. #endif
  62. #endif
  63. /* END specific definitions */
  64.  
  65.  
  66.  
  67. // DΘbuggage de contr⌠le
  68. #if HTS_DEBUG_CLOSESOCK
  69. #define _HTS_WIDE 1
  70. #endif
  71. #if HTS_WIDE_DEBUG
  72. #define _HTS_WIDE 1
  73. #endif
  74. #if _HTS_WIDE
  75. FILE* DEBUG_fp=NULL;
  76. #define DEBUG_W(A)  { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
  77. #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
  78. #endif
  79.  
  80. /* variables globales */
  81. int _DEBUG_HEAD;
  82. FILE* ioinfo;
  83.  
  84. /* dΘtection complΘmentaire */
  85. const char hts_detect[][32] = {
  86.   "archive",
  87.   "background",
  88.   "dynsrc",
  89.   "lowsrc",
  90.   "src",
  91.   "url",
  92.   ""
  93. };
  94.  
  95. /* dΘtection de mini-code javascript */
  96. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  97. const char hts_detect_js[][32] = {
  98.   "onAbort",
  99.   "onBlur",
  100.   "onChange",
  101.   "onClick",
  102.   "onDblClick",
  103.   "onDragDrop",
  104.   "onError",
  105.   "onFocus",
  106.   "onKeyDown",
  107.   "onKeyPress",
  108.   "onKeyUp",
  109.   "onLoad",
  110.   "onMouseDown",
  111.   "onMouseMove",
  112.   "onMouseOut",
  113.   "onMouseOver",
  114.   "onMouseUp",
  115.   "onMove",
  116.   "onReset",
  117.   "onResize",
  118.   "onSelect",
  119.   "onSubmit",
  120.   "onUnload",
  121.   ""
  122. };
  123.  
  124. /* dΘtection "...URL=<url>" */
  125. const char hts_detectURL[][32] = {
  126.   "content",
  127.   ""
  128. };
  129.  
  130. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  131. const char hts_detectandleave[][32] = {
  132.   "action",
  133.   ""
  134. };
  135.  
  136. /* ne pas renommer les types renvoyΘs (couvent types inconnus) */
  137. const char hts_mime_keep[][32] = {
  138.   "application/octet-stream",
  139.   "text/plain",
  140.   ""
  141. };
  142.  
  143. /* pas de type mime connu, mais extension connue */
  144. const char hts_ext_dynamic[][32] = {
  145.   "php3",
  146.   "php",
  147.   "php4",
  148.   "php2",
  149.   "cgi",
  150.   "asp",
  151.   "pl",
  152.   "exe",
  153.   ""
  154. };
  155.  
  156. /* types MIME */
  157. const char hts_mime[][2][32] = {
  158.   {"application/acad","dwg"},
  159.   {"application/arj","arj"},
  160.   {"application/clariscad","ccad"},
  161.   {"application/drafting","drw"},
  162.   {"application/dxf","dxf"},
  163.   {"application/excel","xl"},
  164.   {"application/i-deas","unv"},
  165.   {"application/iges","isg"},
  166.   {"application/iges","iges"},
  167.   {"application/mac-binhex40","hqx"},
  168.   {"application/mac-compactpro","cpt"},
  169.   {"application/msword","word"},
  170.   {"application/msword","w6w"},
  171.   {"application/msword","doc"},
  172.   {"application/mswrite","wri"},
  173.   /*{"application/octet-stream","dms"},*/
  174.   /*{"application/octet-stream","lzh"},*/
  175.   /*{"application/octet-stream","lha"},*/
  176.   /*{"application/octet-stream","bin"},*/
  177.   {"application/oda","oda"},
  178.   {"application/pdf","pdf"},
  179.   {"application/postscript","ai"},
  180.   {"application/postscript","ps"},
  181.   {"application/postscript","eps"},
  182.   {"application/powerpoint","ppt"},
  183.   {"application/pro_eng","prt"},
  184.   {"application/pro_eng","part"},
  185.   {"application/rtf","rtf"},
  186.   {"application/set","set"},
  187.   {"application/sla","stl"},
  188.   {"application/smil","smi"},
  189.   {"application/smil","smil"},
  190.   {"application/smil","sml"},
  191.   {"application/solids","sol"},
  192.   {"application/STEP","stp"},
  193.   {"application/STEP","step"},
  194.   {"application/vda","vda"},
  195.   {"application/x-authorware-map","aam"},     
  196.   {"application/x-authorware-seg","aas"},
  197.   {"application/x-authorware-bin","aab"},
  198.   {"application/x-cocoa","cco"},
  199.   {"application/x-csh","csh"},
  200.   {"application/x-director","dir"},
  201.   {"application/x-director","dcr"},
  202.   {"application/x-director","dxr"},
  203.   {"application/x-mif","mif"},
  204.   {"application/x-dvi","dvi"},
  205.   {"application/x-gzip","gz"},
  206.   {"application/x-gzip","gzip"},
  207.   {"application/x-hdf","hdf"},
  208.   {"application/x-javascript","js"},
  209.   {"application/x-koan","skp"},
  210.   {"application/x-koan","skd"},
  211.   {"application/x-koan","skt"},
  212.   {"application/x-koan","skm"},
  213.   {"application/x-latex","latex"},
  214.   {"application/x-netcdf","nc"},
  215.   {"application/x-netcdf","cdf"},
  216.   /* {"application/x-sh","sh"}, */
  217.   /* {"application/x-csh","csh"}, */
  218.   /* {"application/x-ksh","ksh"}, */
  219.   {"application/x-shar","shar"},
  220.   {"application/x-stuffit","sit"},
  221.   {"application/x-tcl","tcl"},
  222.   {"application/x-tex","tex"},
  223.   {"application/x-texinfo","texinfo"},
  224.   {"application/x-texinfo","texi"},
  225.   {"application/x-troff","t"},
  226.   {"application/x-troff","tr"},
  227.   {"application/x-troff","roff"},
  228.   {"application/x-troff-man","man"},
  229.   {"application/x-troff-me","ms"},
  230.   {"application/x-wais-source","src"},
  231.   {"application/zip","zip"},
  232.   {"application/x-bcpio","bcpio"},
  233.   {"application/x-cdlink","vcd"},
  234.   {"application/x-cpio","cpio"},
  235.   {"application/x-gtar","tgz"},
  236.   {"application/x-gtar","gtar"},
  237.   {"application/x-shar","shar"},
  238.   {"application/x-shockwave-flash","swf"},
  239.   {"application/x-sv4cpio","sv4cpio"},
  240.   {"application/x-sv4crc","sv4crc"},
  241.   {"application/x-tar","tar"},
  242.   {"application/x-ustar","ustar"},
  243.   {"application/x-winhelp","hlp"},
  244.   {"audio/midi","mid"},
  245.   {"audio/midi","midi"},
  246.   {"audio/midi","kar"},
  247.   {"audio/mpeg","mp3"},
  248.   {"audio/mpeg","mpga"},
  249.   {"audio/mpeg","mp2"},
  250.   {"audio/basic","au"},
  251.   {"audio/basic","snd"},
  252.   {"audio/x-aiff","aif"},
  253.   {"audio/x-aiff","aiff"},
  254.   {"audio/x-aiff","aifc"},
  255.   {"audio/x-pn-realaudio","ra"},
  256.   {"audio/x-pn-realaudio","ram"},
  257.   {"audio/x-pn-realaudio","rm"},
  258.   {"audio/x-pn-realaudio-plugin","rpm"},
  259.   {"audio/x-wav","wav"},
  260.   {"chemical/x-pdb","pdb"},
  261.   {"chemical/x-pdb","xyz"},
  262.   {"drawing/x-dwf","dwf"},
  263.   {"image/gif","gif"},
  264.   {"image/ief","ief"},
  265.   {"image/jpeg","jpg"},
  266.   {"image/jpeg","jpe"},
  267.   {"image/jpeg","jpeg"},
  268.   {"image/pict","pict"},
  269.   {"image/png","png"},
  270.   {"image/tiff","tiff"},
  271.   {"image/tiff","tif"},
  272.   {"image/x-cmu-raster","ras"},
  273.   {"image/x-freehand","fh4"},
  274.   {"image/x-freehand","fh7"},
  275.   {"image/x-freehand","fh5"},  
  276.   {"image/x-freehand","fhc"},
  277.   {"image/x-freehand","fh"},   
  278.   {"image/x-portable-anymap","pnm"},
  279.   {"image/x-portable-bitmap","pgm"},
  280.   {"image/x-portable-pixmap","ppm"},
  281.   {"image/x-rgb","rgb"},
  282.   {"image/x-xbitmap","xbm"},
  283.   {"image/x-xpixmap","xpm"},
  284.   {"image/x-xwindowdump","xwd"},
  285.   {"model/mesh","msh"},  
  286.   {"model/mesh","mesh"},  
  287.   {"model/mesh","silo"},  
  288.   {"multipart/x-zip","zip"},
  289.   {"multipart/x-gzip","gzip"},
  290.   {"text/css","css"},
  291.   {"text/html","html"},
  292.   {"text/html","htm"},
  293.   {"text/plain","txt"},
  294.   {"text/plain","g"},
  295.   {"text/plain","h"},
  296.   {"text/plain","c"},
  297.   {"text/plain","cc"},
  298.   {"text/plain","hh"},
  299.   {"text/plain","m"},
  300.   {"text/plain","f90"},
  301.   {"text/richtext","rtx"},
  302.   {"text/tab-separated-values","tsv"},
  303.   {"text/x-setext","etx"},
  304.   {"text/x-sgml","sgml"},
  305.   {"text/x-sgml","sgm"},
  306.   {"text/xml","xml"},  
  307.   {"text/xml","dtd"},  
  308.   {"video/mpeg","mpeg"},
  309.   {"video/mpeg","mpg"},
  310.   {"video/mpeg","mpe"},
  311.   {"video/quicktime","qt"},
  312.   {"video/quicktime","mov"},
  313.   {"video/x-msvideo","avi"},
  314.   {"video/x-sgi-movie","movie"},
  315.   {"x-conference/x-cooltalk","ice"},
  316.   /*{"application/x-httpd-cgi","cgi"},*/
  317.   {"x-world/x-vrml","wrl"},
  318.   
  319.   {"*","class"},
  320.   
  321.   {"",""}};
  322.  
  323.  
  324. // Reserved (RFC2396)
  325. #define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  326. // Delimiters (RFC2396)
  327. #define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  328. // Unwise (RFC2396)
  329. #define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  330. // Special (escape chars) (RFC2396 + >127 )
  331. #define CHAR_SPECIAL(c)   ( ((unsigned char)(c) >= 127) || ((unsigned char)(c) <= 31) )
  332. // We try to avoid them
  333. #define CHAR_XXAVOID(c)   ( strchr(" *'",(unsigned char)(c)) != 0 )
  334.  
  335.   
  336. // conversion Θventuelle / vers antislash
  337. #if HTS_WIN
  338. char* antislash(char* s) {
  339.   static char buff[HTS_URLMAXSIZE*2];
  340.   static char* a;
  341.   strcpy(buff,s);
  342.   while(a=strchr(buff,'/')) *a='\\';
  343.   return buff;
  344. }
  345. #endif
  346.  
  347.  
  348.  
  349. // RΘcupΘration d'un fichier http sur le net.
  350. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  351. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  352. //
  353. // Une adresse de structure htsmsg peut Ωtre transmise pour
  354. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  355. // en background
  356.  
  357. htsblk httpget(char* url) {
  358.   char adr[HTS_URLMAXSIZE*2];   // adresse
  359.   char fil[HTS_URLMAXSIZE*2];   // chemin
  360.   
  361.   // sΘparer URL en adresse+chemin
  362.   if (ident_url(url,adr,fil)==-1) {
  363.     htsblk retour;
  364.     bzero((char *)&retour, sizeof(htsblk));    // effacer
  365.     // retour prΘdΘfini: erreur
  366.     retour.adr=NULL;
  367.     retour.size=0;
  368.     retour.msg[0]='\0';
  369.     retour.statuscode=-1;    
  370.     strcpy(retour.msg,"Error invalid URL");
  371.     return retour;
  372.   }
  373.   
  374.   return xhttpget(adr,fil);
  375. }
  376.  
  377. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  378. // retour: socket
  379. int http_fopen(char* adr,char* fil,htsblk* retour) {
  380.   //                / GET, traiter en-tΩte
  381.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  382. }
  383.  
  384. // ouverture d'une liaison http, envoi d'une requΦte
  385. // mode: 0 GET  1 HEAD  [2 POST]
  386. // treat: traiter header?
  387. // waitconnect: attendre le connect()
  388. // note: dans retour, on met les params du proxy
  389. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  390.   //htsblk retour;
  391.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  392.   T_SOC soc=INVALID_SOCKET;
  393.   //char *p,*q;
  394.   
  395.   // retour prΘdΘfini: erreur
  396.   if (retour) {
  397.     retour->adr=NULL;
  398.     retour->size=0;
  399.     retour->msg[0]='\0';
  400.     retour->statuscode=-5;          // a priori erreur non fatale
  401.   }
  402.  
  403. #if HDEBUG
  404.   printf("adr=%s\nfichier=%s\n",adr,fil);
  405. #endif
  406.   
  407.   // ouvrir liaison
  408. #if HDEBUG
  409.   printf("CrΘation d'une socket sur %s\n",adr);
  410. #endif
  411.  
  412. #if CNXDEBUG
  413.   printf("..newhttp\n");
  414. #endif
  415.  
  416.   /* connexion */
  417.   if (retour) {
  418.     if ( (!(retour->req.proxy.active)) || (strcmp(adr,"file://")==0) ){    /* pas de proxy, ou non utilisable ici */
  419.       soc=newhttp(adr,retour,-1,waitconnect);
  420.     } else {
  421.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  422.     }
  423.   } else {
  424.     soc=newhttp(adr,NULL,-1,waitconnect);    
  425.   }
  426.  
  427.   // copier index socket retour
  428.   if (retour) retour->soc=soc;
  429.  
  430.   // --------------------
  431.   // court-circuit (court circuite aussi le proxy..)
  432.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  433.   if (soc==LOCAL_SOCKET_ID) {
  434.     retour->is_file=1;  // fichier local
  435.     if (mode==0) {    // GET
  436.  
  437.       // Test en cas de file:///C|...
  438.       if (!fexist(fconv(unescape_http(fil))))
  439.         if (fexist(fconv(unescape_http(fil+1)))) {
  440.           char tempo[HTS_URLMAXSIZE*2];
  441.           strcpy(tempo,fil+1);
  442.           strcpy(fil,tempo);
  443.         }
  444.  
  445.       // Ouvrir
  446.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  447.       retour->msg[0]='\0';
  448.       soc=INVALID_SOCKET;
  449.       if (retour->totalsize<0)
  450.         strcpy(retour->msg,"Unable to open file");
  451.       else if (retour->totalsize==0)
  452.         strcpy(retour->msg,"File empty");
  453.       else {
  454.         // Note: On passe par un FILE* (plus propre)
  455.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  456.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  457.         if (retour->fp==NULL)
  458.           soc=INVALID_SOCKET;
  459.         else
  460.           soc=LOCAL_SOCKET_ID;
  461.       }
  462.       retour->soc=soc;
  463.       if (soc!=INVALID_SOCKET) {
  464.         retour->statuscode=200;   // OK
  465.         strcpy(retour->msg,"OK");
  466.         guess_httptype(retour->contenttype,fil);
  467.       } else if (strnotempty(retour->msg)==0)
  468.           strcpy(retour->msg,"Unable to open file");
  469.       return soc;  // renvoyer
  470.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  471.       strcpy(retour->msg,"Unexpected Head/Post local request");
  472.       soc=INVALID_SOCKET;    // erreur
  473.       retour->soc=soc;
  474.       return soc;
  475.     }
  476.   } 
  477.   // --------------------
  478.  
  479.   if (soc!=INVALID_SOCKET) {    
  480.     char rcvd[1100];
  481.     rcvd[0]='\0';
  482. #if HDEBUG
  483.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  484. #endif
  485.     
  486.     // connectΘ?
  487.     if (waitconnect) {
  488.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  489.     } 
  490.     
  491.     if (soc!=INVALID_SOCKET) {
  492.       
  493. #if HDEBUG
  494.       printf("Attente de la rΘponse:\n");
  495. #endif
  496.       
  497.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  498.       // et ensuite le corps
  499.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  500.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  501.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  502.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  503.         
  504.         // status-line α rΘcupΘrer
  505.         finput(soc,rcvd,1024);
  506.         if (strnotempty(rcvd)==0)
  507.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  508.  
  509.         // traiter status-line
  510.         treatfirstline(retour,rcvd);
  511.  
  512. #if HDEBUG
  513.         printf("Status-Code=%d\n",retour->statuscode);
  514. #endif
  515.         
  516.         // en-tΩte
  517.         
  518.         // header // ** !attention! HTTP/0.9 non supportΘ
  519.         do {
  520.           finput(soc,rcvd,1024);          
  521. #if HDEBUG
  522.           printf(">%s\n",rcvd);      
  523. #endif
  524.           if (strnotempty(rcvd))
  525.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  526.  
  527.         } while(strnotempty(rcvd));
  528.         
  529.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  530.         
  531.         //if (retour)
  532.         //  retour->totalsize=rcvsize;
  533.         
  534.       } else { // si GET, on recevra l'en tΩte APRES
  535.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  536.         if (retour)
  537.           retour->totalsize=-1;
  538.       }
  539.       
  540.     }
  541.  
  542.   }
  543.     
  544.   return soc;
  545. }
  546.  
  547.  
  548. // envoi d'une requΦte
  549. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  550.   char buff[8192];
  551.   //int use_11=0;     // HTTP 1.1 utilisΘ
  552.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  553.   char* search_tag=NULL;
  554.   buff[0]='\0';
  555.  
  556.   // header Date
  557.   //strcat(buff,"Date: ");
  558.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  559.   //sendc("\n");
  560.   //strcat(buff,buff);
  561.  
  562.   // possibilitΘ non documentΘe: >post: et >postfile:
  563.   // si prΘsence d'un tag >post: alors executer un POST
  564.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  565.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  566.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  567.   search_tag=strstr(fil,POSTTOK":");
  568.   if (!search_tag) {
  569.     search_tag=strstr(fil,POSTTOK"file:");
  570.     if (search_tag) {     // postfile
  571.       if (mode==0) {      // GET!
  572.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  573.         if (fp) {
  574.           char line[1100];
  575.           char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  576.           linput(fp,line,1000);
  577.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  578.             // selon que l'on a ou pas un proxy
  579.             if (retour->req.proxy.active)
  580.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  581.             else
  582.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  583.             // lire le reste en brut
  584.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  585.           }
  586.           fclose(fp);
  587.         }
  588.       }
  589.     }
  590.   }
  591.   // Fin postfile
  592.   
  593.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  594.     // Type de requΦte?
  595.     if ((search_tag) && (mode==0)) {
  596.       strcat(buff,"POST ");
  597.     } else if (mode==0) {    // GET
  598.       strcat(buff,"GET ");
  599.     } else {  // if (mode==1) {
  600.       if (!retour->req.http11)        // forcer HTTP/1.0
  601.         strcat(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  602.       else
  603.         strcat(buff,"HEAD ");
  604.     }
  605.     
  606.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  607.     if (retour->req.proxy.active) {
  608.       if (strncmp(adr,"ftp://",6)!=0) {
  609. #if HDEBUG
  610.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  611. #endif
  612.         strcat(buff,"http://");
  613.         strcat(buff,jump_identification(adr));
  614.       } else {          // ftp:// en proxy http
  615. #if HDEBUG
  616.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  617. #endif
  618.         direct_url=1;             // ne pas analyser user/pass
  619.         strcat(buff,adr);
  620.       }
  621.     } 
  622.     
  623.     // NOM DU FICHIER
  624.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  625.     if (*fil!='/') strcat(buff,"/");
  626.     {
  627.       char tempo[HTS_URLMAXSIZE*2];
  628.       tempo[0]='\0';
  629.       if (search_tag)
  630.         strncat(tempo,fil,(int) search_tag -(int) fil);
  631.       else
  632.         strcpy(tempo,fil);
  633.       escape_check_url(tempo);
  634.       strcat(buff,tempo);       // avec Θchappement
  635.     }
  636.     
  637.     // protocole
  638.     if (!retour->req.http11) {     // forcer HTTP/1.0
  639.       //use_11=0;
  640.       strcat(buff," HTTP/1.0\x0d\x0a");
  641.     } else {                   // RequΦte 1.1
  642.       //use_11=1;
  643.       strcat(buff," HTTP/1.1\x0d\x0a");
  644.     }
  645.  
  646.     /* supplemental data */
  647.     if (xsend) strcat(buff,xsend);    // Θventuelles autres lignes
  648.  
  649.     // tester proxy authentication
  650.     if (retour->req.proxy.active) {
  651.       char* a=jump_identification(retour->req.proxy.name);
  652.       if (a!=retour->req.proxy.name) {  // et hop, authentification proxy!
  653.         char autorisation[1100];
  654.         char user_pass[256];        
  655.         autorisation[0]=user_pass[0]='\0';
  656.         //
  657.         strncat(user_pass,retour->req.proxy.name,(int) a - (int) retour->req.proxy.name - 1);
  658.         strcpy(user_pass,unescape_http(user_pass));
  659.         code64(user_pass,autorisation);
  660.         strcat(buff,"Proxy-Authorization: Basic ");
  661.         strcat(buff,autorisation);
  662.         strcat(buff,H_CRLF);
  663. #if HDEBUG
  664.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  665. #endif
  666.       }
  667.     }
  668.     
  669.     // Referer?
  670.     if ((referer_adr) && (referer_fil)) {       // existe
  671.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  672.         if (strcmp(referer_adr,"file://")) {      // PAS file://
  673.           strcat(buff,"Referer: ");
  674.           strcat(buff,"http://");
  675.           strcat(buff,referer_adr);
  676.           strcat(buff,referer_fil);
  677.           strcat(buff,H_CRLF);
  678.         }
  679.       }
  680.     }
  681.     
  682.     // POST?
  683.     if (mode==0) {      // GET!
  684.       if (search_tag) {
  685.         char clen[256];
  686.         sprintf(clen,"Content-length: %d"H_CRLF,strlen(unescape_http(search_tag+strlen(POSTTOK)+1)));
  687.         strcat(buff,clen);
  688.       }
  689.     }
  690.     
  691.     // gestion cookies?
  692.     if (cookie) {
  693.       char* b=cookie->data;
  694.       int cook=0;
  695.       int max_cookies=8;
  696.       int max_size=2048;
  697.       max_size+=strlen(buff);
  698.       do {
  699.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  700.         if (b) {
  701.           max_cookies--;
  702.           if (!cook) {
  703.             strcat(buff,"Cookie: ");
  704.             strcat(buff,"$Version=1; ");
  705.             cook=1;
  706.           } else
  707.             strcat(buff,"; ");
  708.           strcat(buff,cookie_get(b,5));
  709.           strcat(buff,"=");
  710.           strcat(buff,cookie_get(b,6));
  711.           strcat(buff,"; $Path=");
  712.           strcat(buff,cookie_get(b,2));
  713.           b=cookie_nextfield(b);
  714.         }
  715.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  716.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  717.         strcat(buff,H_CRLF);
  718. #if DEBUG_COOK
  719.         printf("Header:\n%s\n",buff);
  720. #endif
  721.       }
  722.     }
  723.     
  724.     // connection close?
  725.     //if (use_11)     // Si on envoie une requΦte 1.1, prΘciser qu'on ne veut pas de keep-alive!!
  726.     strcat(buff,"Connection: close"H_CRLF);
  727.     
  728.     //strcat(buff,"Referer: http://");ppp
  729.     //strcat(buff,adr); 
  730.     //strcat(buff,"\n");
  731.     
  732.     // gΘrer le keep-alive (garder socket)
  733.     //strcat(buff,"Connection: Keep-Alive\n");
  734.     
  735.     {
  736.       char* real_adr=jump_identification(adr);
  737.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  738.       if (!direct_url) {     // pas ftp:// par exemple
  739.         //if (!retour->req.proxy.active) {
  740.         strcat(buff,"Host: "); strcat(buff,real_adr); strcat(buff,H_CRLF);
  741.         //}
  742.       }
  743.       //}
  744.  
  745.       // PrΘsence d'un user-agent?
  746.       if (retour->req.user_agent_send) {  // ohh un user-agent
  747.         char s[256];
  748.         // HyperTextSeeker/"HTSVERSION
  749.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  750.         strcat(buff,s);
  751.         
  752.         // pour les serveurs difficiles
  753.         strcat(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"H_CRLF);
  754.         if (strnotempty(retour->req.lang_iso)) {
  755.           strcat(buff,"Accept-Language: "); strcat(buff,retour->req.lang_iso); strcat(buff,H_CRLF);
  756.         }
  757.         strcat(buff,"Accept-Charset: iso-8859-1, *"H_CRLF);   
  758.         strcat(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  759.       } else {
  760.         strcat(buff,"Accept: */*"H_CRLF);         // le minimum
  761.       }
  762.  
  763.       /* Authentification */
  764.       {
  765.         char autorisation[1100];
  766.         char* a;
  767.         autorisation[0]='\0';
  768.         if (real_adr != adr) {  // ohh une authentification!
  769.           if (!direct_url) {      // pas ftp:// par exemple
  770.             char user_pass[256];
  771.             user_pass[0]='\0';
  772.             strncat(user_pass,adr,(int) real_adr - (int) adr - 1);
  773.             strcpy(user_pass,unescape_http(user_pass));
  774.             code64(user_pass,autorisation);
  775.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  776.               bauth_add(cookie,real_adr,fil,autorisation);
  777.           }
  778.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  779.           strcpy(autorisation,a);
  780.         /* On a une autorisation a donner?  */
  781.         if (strnotempty(autorisation)) {
  782.           strcat(buff,"Authorization: Basic ");
  783.           strcat(buff,autorisation);
  784.           strcat(buff,H_CRLF);
  785.         }
  786.       }
  787.  
  788.     }
  789.     //strcat(buff,"Accept-Language: en\n");
  790.     //strcat(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  791.     
  792.     // CRLF de fin d'en tΩte
  793.     strcat(buff,H_CRLF);
  794.     
  795.     // donnΘes complΘmentaires?
  796.     if (search_tag)
  797.     if (mode==0)      // GET!
  798.       strcat(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  799.   }
  800.   
  801. #if HDEBUG
  802. #endif
  803.   if (_DEBUG_HEAD) {
  804.     if (ioinfo) {
  805.       fprintf(ioinfo,"Out:\r\n%s\r\n",buff);
  806.       fflush(ioinfo);
  807.     }
  808.   }  // Fin test pas postfile
  809.   //
  810.  
  811.   // Envoi
  812.   if (sendc(retour->soc,buff)<0) {  // ERREUR, socket rompue?...
  813.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  814.     deletesoc(retour->soc);  // fermer tout de mΩme
  815.     // et tenter de reconnecter
  816.     
  817.     strcpy(retour->msg,"Broken pipe");
  818.     retour->soc=INVALID_SOCKET;
  819.     /* non, α cause du poll connect()
  820.     // si on avait une connexion proxy, tenter une connexion directe cette fois!
  821.     retour->proxy.active=0;
  822.     if (retour) {
  823.     soc=newhttp(adr,retour->msg,-1,1);
  824.     retour->soc=soc;
  825.     }
  826.     else {
  827.     soc=newhttp(adr,NULL,-1,1);   
  828.     }
  829.     
  830.       // reconnectΘ?
  831.       if (soc!=INVALID_SOCKET) {        
  832.       if (sendc(soc,buff)<0) {  // NAN MARCHE PAS
  833.       strcpy(retour->msg,"Can not write to a re-established socket connexion");
  834.       deletesoc(soc);  // fermer tout de mΩme
  835.       soc=INVALID_SOCKET;
  836.       }
  837.       
  838.         } else {
  839.         strcpy(retour->msg,"Can not re-establish a socket connexion");
  840.         }
  841.     */
  842.   }
  843.   
  844.   // RX'98
  845.   return 0;
  846. }
  847.  
  848.  
  849.  
  850.  
  851. // traiter 1ere ligne d'en tΩte
  852. void treatfirstline(htsblk* retour,char* rcvd) {
  853.   char* a=rcvd;
  854.   // exemple:
  855.   // HTTP/1.0 200 OK
  856.   if (*a) {
  857.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  858.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  859.     // sauter HTTP/1.x
  860.     while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  861.     if (*a != '\0') {
  862.       while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  863.       if ((*a>='0') && (*a<='9')) {
  864.         sscanf(a,"%d",&(retour->statuscode));
  865.         // sauter 200
  866.         while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  867.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  868.         if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  869.           strcpy(retour->msg,a);
  870.         else
  871.           infostatuscode(retour->msg,retour->statuscode);
  872.         // type MIME par dΘfaut
  873.         strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  874.       } else {  // pas de code!
  875.         retour->statuscode=-1;
  876.         strcpy(retour->msg,"Unknown response structure");
  877.       }
  878.     } else {  // euhh??
  879.       retour->statuscode=-1;
  880.       strcpy(retour->msg,"Unknown response structure");
  881.     }
  882.   } else {  // vide!
  883.     retour->statuscode=-1;
  884.     strcpy(retour->msg,"Empty reponse or internal error");
  885.   }
  886. }
  887.  
  888. // traiter ligne par ligne l'en tΩte
  889. // gestion des cookies
  890. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  891.   int p;
  892.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  893. #if HDEBUG
  894.     printf("ok, Content-length: dΘtectΘ\n");
  895. #endif
  896.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  897.   }
  898.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  899.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  900.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  901.       char tmp[256];
  902.       char *a=NULL,*b=NULL;
  903.       strcpy(tmp,rcvd+p);
  904.       a=strstr(tmp,"filename=");
  905.       if (a) {
  906.         a+=strlen("filename=");
  907.         while(is_space(*a)) a++;
  908.         //a=strchr(a,'"');
  909.         if (a) {
  910.           char *c=NULL;
  911.           //a++;      /* jump " */
  912.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  913.             a=c+1;
  914.           //b=strchr(a+1,'"');
  915.           b=a+strlen(a)-1;
  916.           while(is_space(*b)) b--;
  917.           b++;
  918.           if (b) {
  919.             *b='\0';
  920.             if ((int) strlen(a) < 200) { // pas trop long?
  921.               strcpy(retour->cdispo,a);
  922.             }
  923.           }
  924.         }
  925.       } 
  926.     }
  927.   }
  928.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  929.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  930.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  931.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  932.       strcpy(retour->lastmodified,rcvd+p);
  933.     }
  934.   }
  935.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  936.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  937.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  938.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  939.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  940.         strcpy(retour->lastmodified,rcvd+p);
  941.       }
  942.     }
  943.   }
  944.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  945.     if (retour) {
  946.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  947.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  948.         strcpy(retour->etag,rcvd+p);
  949.       else    // erreur.. ignorer
  950.         retour->etag[0]='\0';
  951.     }
  952.   }
  953.   else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  954.     retour->is_chunk=1;     // chunked
  955.     //retour->http11=2;     // chunked
  956. #if HDEBUG
  957.     printf("ok, Transfer-Encoding: dΘtectΘ\n");
  958. #endif
  959.   }
  960.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  961.     if (retour) {
  962.       char tempo[1100];
  963.       // Θviter les text/html; charset=foo
  964.       {
  965.         char* a=strchr(rcvd+p,';');
  966.         if (a) *a='\0';
  967.       }
  968.       sscanf(rcvd+p,"%s",tempo);
  969.       if (strlen(tempo)<64)    // pas trop long!!
  970.         strcpy(retour->contenttype,tempo);
  971.       else
  972.         strcpy(retour->contenttype,"application/octet-stream-unknown");    // erreur
  973.     }
  974.   }
  975.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  976.     if (retour) {
  977.       if (retour->location) {
  978.         while(*(rcvd+p)==' ') p++;    // sauter espaces
  979.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  980.           sscanf(rcvd+p,"%s",retour->location);
  981.         else    // erreur.. ignorer
  982.           retour->location[0]='\0';
  983.       }
  984.     }
  985.   }
  986.   else if ((p=strfield(rcvd,"Connection: Keep-Alive"))!=0) {
  987.     // non, pas de keep-alive! on dΘconnectera..          
  988.   }
  989.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {    // params keep-alive
  990.     // rien α faire          
  991.   }
  992.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  993.     char* a = rcvd+p;           // pointeur
  994.     char domain[256];           // domaine cookie (.netscape.com)
  995.     char path[256];             // chemin (/)
  996.     char cook_name[256];        // nom cookie (MYCOOK)
  997.     char cook_value[8192];      // valeur (ID=toto,S=1234)
  998. #if DEBUG_COOK
  999.     printf("set-cookie detected\n");
  1000. #endif
  1001.     while(*a) {
  1002.       char *token_st,*token_end;
  1003.       char *value_st,*value_end;
  1004.       char name[256];
  1005.       char value[8192];
  1006.       int next=0;
  1007.       name[0]=value[0]='\0';
  1008.       //
  1009.  
  1010.       // initialiser cookie lu actuellement
  1011.       if (adr)
  1012.         strcpy(domain,jump_identification(adr));     // domaine
  1013.       strcpy(path,"/");         // chemin (/)
  1014.       strcpy(cook_name,"");     // nom cookie (MYCOOK)
  1015.       strcpy(cook_value,"");    // valeur (ID=toto,S=1234)
  1016.       // boucler jusqu'au prochain cookie ou la fin
  1017.       do {
  1018.         char* start_loop=a;
  1019.         while(is_space(*a)) a++;    // sauter espaces
  1020.         token_st=a;                 // dΘpart token
  1021.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1022.         token_end=a;
  1023.         while(is_space(*a)) a++;    // sauter espaces
  1024.         if (*a=='=') {    // name=value
  1025.           a++;
  1026.           while(is_space(*a)) a++;    // sauter espaces
  1027.           value_st=a;
  1028.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1029.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1030.           value_end=a;
  1031.           //if (*a==';') {  // finit par un ;
  1032.           // vΘrifier dΘbordements
  1033.           if ( (((int) token_end - (int) token_st)<200) && (((int) value_end - (int) value_st)<8000)
  1034.             && (((int) token_end - (int) token_st)>0)   && (((int) value_end - (int) value_st)>0) ) {
  1035.             name[0]='\0';
  1036.             value[0]='\0';
  1037.             strncat(name,token_st,(int) token_end - (int) token_st);
  1038.             strncat(value,value_st,(int) value_end - (int) value_st);
  1039. #if DEBUG_COOK
  1040.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1041. #endif
  1042.             if (strfield2(name,"domain")) {
  1043.               strcpy(domain,value);
  1044.             }
  1045.             else if (strfield2(name,"path")) {
  1046.               strcpy(path,value);
  1047.             }
  1048.             else if (strfield2(name,"max-age")) {
  1049.               // ignorΘ..
  1050.             }
  1051.             else if (strfield2(name,"expires")) {
  1052.               // ignorΘ..
  1053.             }
  1054.             else if (strfield2(name,"version")) {
  1055.               // ignorΘ..
  1056.             }
  1057.             else if (strfield2(name,"comment")) {
  1058.               // ignorΘ
  1059.             }
  1060.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1061.               // ignorΘ
  1062.             }
  1063.             else {
  1064.               if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1065.                 strcpy(cook_name,name);
  1066.                 strcpy(cook_value,value);
  1067.               } else {                             // prochain cookie
  1068.                 a=start_loop;      // on devra recommencer α cette position
  1069.                 next=1;            // enregistrer
  1070.               }
  1071.             }
  1072.           }
  1073.         }
  1074.         if (!next) {
  1075.           while((*a!=';') && (*a)) a++;    // prochain
  1076.           while(*a==';') a++;             // sauter ;
  1077.         }
  1078.       } while((*a) && (!next));
  1079.       if (strnotempty(cook_name)) {          // cookie?
  1080. #if DEBUG_COOK
  1081.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1082. #endif
  1083.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1084.       }
  1085.     }
  1086.   }
  1087. }
  1088.  
  1089.  
  1090. // transforme le message statuscode en chaεne
  1091. void infostatuscode(char* msg,int statuscode) {
  1092.   switch( statuscode) {    
  1093.     // Erreurs HTTP, selon RFC
  1094.   case 100: strcpy( msg,"Continue"); break; 
  1095.   case 101: strcpy( msg,"Switching Protocols"); break; 
  1096.   case 200: strcpy( msg,"OK"); break; 
  1097.   case 201: strcpy( msg,"Created"); break; 
  1098.   case 202: strcpy( msg,"Accepted"); break; 
  1099.   case 203: strcpy( msg,"Non-Authoritative Information"); break; 
  1100.   case 204: strcpy( msg,"No Content"); break; 
  1101.   case 205: strcpy( msg,"Reset Content"); break; 
  1102.   case 206: strcpy( msg,"Partial Content"); break; 
  1103.   case 300: strcpy( msg,"Multiple Choices"); break; 
  1104.   case 301: strcpy( msg,"Moved Permanently"); break; 
  1105.   case 302: strcpy( msg,"Moved Temporarily"); break; 
  1106.   case 303: strcpy( msg,"See Other"); break; 
  1107.   case 304: strcpy( msg,"Not Modified"); break; 
  1108.   case 305: strcpy( msg,"Use Proxy"); break; 
  1109.   case 306: strcpy( msg,"Undefined 306 error"); break; 
  1110.   case 307: strcpy( msg,"Temporary Redirect"); break; 
  1111.   case 400: strcpy( msg,"Bad Request"); break; 
  1112.   case 401: strcpy( msg,"Unauthorized"); break; 
  1113.   case 402: strcpy( msg,"Payment Required"); break; 
  1114.   case 403: strcpy( msg,"Forbidden"); break; 
  1115.   case 404: strcpy( msg,"Not Found"); break; 
  1116.   case 405: strcpy( msg,"Method Not Allowed"); break; 
  1117.   case 406: strcpy( msg,"Not Acceptable"); break; 
  1118.   case 407: strcpy( msg,"Proxy Authentication Required"); break; 
  1119.   case 408: strcpy( msg,"Request Time-out"); break; 
  1120.   case 409: strcpy( msg,"Conflict"); break; 
  1121.   case 410: strcpy( msg,"Gone"); break; 
  1122.   case 411: strcpy( msg,"Length Required"); break; 
  1123.   case 412: strcpy( msg,"Precondition Failed"); break; 
  1124.   case 413: strcpy( msg,"Request Entity Too Large"); break; 
  1125.   case 414: strcpy( msg,"Request-URI Too Large"); break; 
  1126.   case 415: strcpy( msg,"Unsupported Media Type"); break; 
  1127.   case 416: strcpy( msg,"Requested Range Not Satisfiable"); break; 
  1128.   case 417: strcpy( msg,"Expectation Failed"); break; 
  1129.   case 500: strcpy( msg,"Internal Server Error"); break; 
  1130.   case 501: strcpy( msg,"Not Implemented"); break; 
  1131.   case 502: strcpy( msg,"Bad Gateway"); break; 
  1132.   case 503: strcpy( msg,"Service Unavailable"); break; 
  1133.   case 504: strcpy( msg,"Gateway Time-out"); break; 
  1134.   case 505: strcpy( msg,"HTTP Version Not Supported"); break; 
  1135.     //
  1136.   default: if (strnotempty(msg)==0) strcpy( msg,"Unknown error"); break;
  1137.   }
  1138. }
  1139.  
  1140.  
  1141. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1142. htsblk xhttpget(char* adr,char* fil) {
  1143.   T_SOC soc;
  1144.   htsblk retour;
  1145.   
  1146.   bzero((char *)&retour, sizeof(htsblk));
  1147.   soc=http_fopen(adr,fil,&retour);
  1148.  
  1149.   if (soc!=INVALID_SOCKET) {
  1150.     http_fread(soc,&retour);
  1151. #if HTS_DEBUG_CLOSESOCK
  1152.     DEBUG_W("xhttpget: deletehttp\n");
  1153. #endif
  1154.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1155.     retour.soc=INVALID_SOCKET;
  1156.   }
  1157.   return retour;
  1158. }
  1159.  
  1160. // variation sur un thΦme...
  1161. // rΘceptionne uniquement un en-tΩte (HEAD)
  1162. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1163. htsblk http_gethead(char* adr,char* fil) {
  1164.   T_SOC soc;
  1165.   htsblk retour;
  1166.  
  1167.   bzero((char *)&retour, sizeof(htsblk));
  1168.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1169.  
  1170.   if (soc!=INVALID_SOCKET) {
  1171.     http_fread(soc,&retour);    // rΘception en-tΩte
  1172. #if HTS_DEBUG_CLOSESOCK
  1173.     DEBUG_W("http_gethead: deletehttp\n");
  1174. #endif
  1175.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1176.     retour.soc=INVALID_SOCKET;
  1177.   }
  1178.   return retour;
  1179. }
  1180. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1181.  
  1182.  
  1183. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1184. // il ne reste plus qu'α lire les donnΘes
  1185. // (pour HEAD le header est lu ici!)
  1186. void http_fread(T_SOC soc,htsblk* retour) {  
  1187.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1188.   
  1189.   if (retour) retour->soc=soc;
  1190.   if (soc!=INVALID_SOCKET) {    
  1191.     // fonction de lecture d'une socket (plus propre)
  1192.     while(http_fread1(retour)!=-1);
  1193.     soc=retour->soc;
  1194.     if (retour->adr==NULL) {
  1195.       if (strnotempty(retour->msg)==0)
  1196.         sprintf(retour->msg,"Unable to read");
  1197.       return ;    // erreur
  1198.     } 
  1199.     
  1200. #if HDEBUG
  1201.     printf("Ok, donnΘes reτues\n");
  1202. #endif   
  1203.  
  1204.     return ;
  1205.     
  1206.   } 
  1207.   
  1208.   return ;
  1209. }
  1210.  
  1211. // lecture d'un bloc sur une socket (ou un fichier!)
  1212. HTS_INLINE LLint http_fread1(htsblk* r) {
  1213.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1214.   return http_xfread1(r,TAILLE_BUFFER);
  1215. }
  1216.  
  1217. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1218. // SI bufl=0 alors le buffer est censΘ Ωtre de 8kos, et on recoit caractΦres
  1219. // par caractΦres en Θliminant les cr (ex: header)
  1220. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1221. LLint http_xfread1(htsblk* r,int bufl) {
  1222.   int nl=-1;
  1223.  
  1224.   if (bufl>0) {
  1225.     if (!r->is_write) {     // stocker en mΘmoire
  1226.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1227.         if (r->adr==NULL) {
  1228.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1229.           r->size=0;
  1230.         }
  1231.         if (r->adr!=NULL) {
  1232.           // lecture
  1233.           nl=hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1234.           // nouvelle taille
  1235.           if (nl>0) r->size+=nl;
  1236.           
  1237.           if ((nl<=0) || (r->size >= r->totalsize))
  1238.             nl=-1;  // break
  1239.           
  1240.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1241.         }
  1242.         
  1243.       } else {                 // inconnu..
  1244.         // rΘserver de la mΘmoire?
  1245.         if (r->adr==NULL) {
  1246. #if HDEBUG
  1247.           printf("..alloc xfread\n");
  1248. #endif
  1249.           r->adr=(char*) malloct(bufl + 1);
  1250.           r->size=0;
  1251.         }
  1252.         else {
  1253. #if HDEBUG
  1254.           printf("..realloc xfread1\n");
  1255. #endif
  1256.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1257.         }
  1258.         
  1259.         if (r->adr!=NULL) {
  1260.           // lecture
  1261.           nl=hts_read(r,r->adr+(int)r->size,bufl);
  1262.           if (nl>0) {
  1263.             // resize
  1264.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1265.             // nouvelle taille
  1266.             if (nl>0) r->size+=nl;
  1267.  
  1268.             if (r->adr) r->adr[r->size]='\0';    // octet nul
  1269.  
  1270.           } // sinon on a fini
  1271. #if HDEBUG
  1272.           else
  1273.             printf("..end read (%d)\n",nl);
  1274. #endif
  1275.         }
  1276. #if HDEBUG
  1277.         else printf("..-> error\n");
  1278. #endif
  1279.       }
  1280.  
  1281.       // pas de adr=erreur
  1282.       if (r->adr==NULL) nl=-1;
  1283.  
  1284.     } else {    // stocker sur disque
  1285.       char* buff;
  1286.       buff=(char*) malloct(bufl);
  1287.       if (buff!=NULL) {
  1288.         // lecture
  1289.         nl=hts_read(r,buff,bufl);
  1290.         // nouvelle taille
  1291.         if (nl>0) { 
  1292.           r->size+=nl;
  1293.           if ((int) fwrite(buff,1,nl,r->out)!=nl) {
  1294.             r->statuscode=-1;
  1295.             strcpy(r->msg,"Write error on disk");
  1296.             nl=-1;
  1297.           }
  1298.         }
  1299.  
  1300.         if ((nl<=0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1301.           nl=-1;  // break
  1302.  
  1303.         // libΘrer bloc tempo
  1304.         freet(buff);
  1305.       } else nl=-1;
  1306.       
  1307.       // NON ce n'est pas notre r⌠le - et cela pose des problΦmes pour la rΘception en chunk
  1308.       /*
  1309.         //if (nl<=0)    // fin
  1310.         //if (r->out!=NULL) { fclose(r->out); r->out=NULL; }
  1311.       */
  1312.       if (nl<=0)    // fin
  1313.       if (r->out!=NULL) { fflush(r->out); }
  1314.         
  1315.         
  1316.     } // stockage disque ou mΘmoire
  1317.  
  1318.   } else {    // rΘception d'un en-tΩte octet par octet
  1319.  
  1320.     if (r->adr==NULL) {
  1321.       r->adr=(char*) malloct(8192);
  1322.       r->size=0;
  1323.     }
  1324.     
  1325.     if (r->adr!=NULL) {
  1326.       // lecture
  1327.       nl=hts_read(r,r->adr+r->size,1);
  1328.       if (nl>0) {
  1329.         if (*(r->adr+r->size) != 13)    // sauter caractΦres 13
  1330.           (r->size)++;
  1331.         *(r->adr+r->size)='\0';    // terminer par octet nul
  1332.       }
  1333.       if (r->size>=8190) {
  1334.         nl=-1;    // break
  1335.       }
  1336.     }
  1337.     // pas de adr=erreur
  1338.     if (r->adr==NULL) nl=-1;
  1339.   }
  1340. #if HDEBUG
  1341.   //printf("add to %d / %d\n",r->size,r->totalsize);
  1342. #endif
  1343.   return ((nl>0)?0:-1);
  1344. }
  1345.  
  1346.  
  1347. // teste une adresse, et suit l'Θventuel chemin "moved"
  1348. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1349. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1350. htsblk http_location(char* adr,char* fil,char* loc) {
  1351.   htsblk retour;
  1352.   int retry=0;
  1353.   int tryagain;
  1354.   // note: "RFC says"
  1355.   // 5 boucles au plus, on en teste au plus 8 ici
  1356.   // sinon abandon..
  1357.   do {
  1358.     tryagain=0;
  1359.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1360.     case 200: break;   // ok!
  1361.     case 301: case 302: case 303: case 307: // moved!
  1362.       // recalculer adr et fil!
  1363.       if (ident_url(loc,adr,fil)!=-1) {
  1364.         tryagain=1;  // retenter
  1365.         retry++;     // ..encore une fois
  1366.       }
  1367.     }
  1368.   } while((tryagain) && (retry<5+3));
  1369.   return retour;
  1370. }
  1371.  
  1372.  
  1373. // teste si une URL (validitΘ, header, taille)
  1374. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1375. // en cas de moved xx, dans location
  1376. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1377. // qui nous font poireauter 5 heures..) -> -2=timeout
  1378. htsblk http_test(char* adr,char* fil,char* loc) {
  1379.   T_SOC soc;
  1380.   htsblk retour;
  1381.   //int rcvsize=-1;
  1382.   //char* rcv=NULL;    // adresse de retour
  1383.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1384.   double tl;
  1385.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1386.  
  1387.   // pour abandonner un site trop lent
  1388.   tl=time_local();
  1389.  
  1390.   loc[0]='\0';
  1391.   bzero((char *)&retour, sizeof(htsblk));    // effacer
  1392.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1393.  
  1394.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1395.  
  1396.   // on ouvre en head, et on traite l'en tΩte
  1397.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1398.   
  1399.   if (soc!=INVALID_SOCKET) {
  1400.     int e=0;
  1401.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1402.     do {
  1403.       if (http_xfread1(&retour,0)==-1)
  1404.         e=1;
  1405.       else {
  1406.         if (retour.adr!=NULL) {
  1407.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1408.             e=1;
  1409.         }
  1410.       }
  1411.             
  1412.       if (!e) {
  1413.         if ((time_local()-tl)>=timeout) {
  1414.           e=-1;
  1415.         }
  1416.       }
  1417.       
  1418.     } while (!e);
  1419.     
  1420.     if (e==1) {
  1421.       if (adr!=NULL) {
  1422.         int ptr=0;
  1423.         char rcvd[1100];
  1424.  
  1425.         // note: en gros recopie du traitement de back_wait()
  1426.         //
  1427.  
  1428.  
  1429.         // ----------------------------------------
  1430.         // traiter en-tΩte!
  1431.         // status-line α rΘcupΘrer
  1432.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1433.         if (strnotempty(rcvd)==0)
  1434.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1435.         
  1436.         // traiter status-line
  1437.         treatfirstline(&retour,rcvd);
  1438.         
  1439. #if HDEBUG
  1440.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1441. #endif
  1442.         
  1443.         // en-tΩte
  1444.         
  1445.         // header // ** !attention! HTTP/0.9 non supportΘ
  1446.         do {
  1447.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  1448. #if HDEBUG
  1449.           printf("(buffer)>%s\n",rcvd);      
  1450. #endif
  1451.           if (strnotempty(rcvd))
  1452.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  1453.           
  1454.         } while(strnotempty(rcvd));
  1455.         // ----------------------------------------                    
  1456.         
  1457.         // libΘrer mΘmoire
  1458.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  1459.       }
  1460.     } else {
  1461.       retour.statuscode=-2;
  1462.       strcpy(retour.msg,"Timeout While Testing");
  1463.     }
  1464.     
  1465.     
  1466. #if HTS_DEBUG_CLOSESOCK
  1467.     DEBUG_W("http_test: deletehttp\n");
  1468. #endif
  1469.     deletehttp(&retour);
  1470.     retour.soc=INVALID_SOCKET;
  1471.   }
  1472.   return retour;    
  1473. }
  1474.  
  1475. // CrΘe un lien (http) vers une adresse internet iadr
  1476. // retour: structure (adresse, taille, message si erreur (si !adr))
  1477. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  1478. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  1479.   T_SOC soc;                           // descipteur de la socket
  1480.   char* iadr;
  1481.   // unsigned short int port;
  1482.   
  1483.   // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  1484.   iadr = jump_identification(_iadr);
  1485.   
  1486.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  1487.   // local.
  1488.   // utile pour les tests!
  1489.   //## if (iadr[0]!=lOCAL_CHAR) {
  1490.   if (strcmp(iadr,"file://")) {           /* non fichier */
  1491.     struct sockaddr_in server;
  1492.     t_hostent* hp;    
  1493.     // effacer structure
  1494.     bzero((char *)&server, sizeof(server));
  1495.  
  1496. #if HDEBUG
  1497.     printf("gethostbyname\n");
  1498. #endif
  1499.     
  1500.     // tester un Θventuel port
  1501.     if (port==-1) {
  1502.       char *a=strchr(iadr,':');
  1503.       port=80;    // port par dΘfaut
  1504.       if (a) {
  1505.         char iadr2[HTS_URLMAXSIZE*2];
  1506.         int i=-1;
  1507.         iadr2[0]='\0';
  1508.         sscanf(a+1,"%d",&i);
  1509.         if (i!=-1) {
  1510.           port=(unsigned short int) i;
  1511.         }
  1512.         
  1513.         // adresse vΘritable (sans :xx)
  1514.         strncat(iadr2,iadr,(int) a-(int) iadr);
  1515.  
  1516.         // adresse sans le :xx
  1517.         hp = hts_gethostbyname(iadr2);
  1518.         
  1519.       } else {
  1520.  
  1521.         // adresse normale (port par dΘfaut par la suite)
  1522.         hp = hts_gethostbyname(iadr);
  1523.         
  1524.       }
  1525.       
  1526.     } else    // port dΘfini
  1527.       hp = hts_gethostbyname(iadr);
  1528.  
  1529.     
  1530.     // Conversion iadr -> adresse
  1531.     // structure recevant le nom de l'h⌠te, etc
  1532.     //struct     hostent     *hp;
  1533.     if (hp == NULL) {
  1534. #if DEBUG
  1535.       printf("erreur gethostbyname\n");
  1536. #endif
  1537.       if (retour)
  1538.       if (retour->msg)
  1539.         strcpy(retour->msg,"Unable to get server's address");
  1540.       return INVALID_SOCKET;
  1541.     }  
  1542.     // copie adresse
  1543.     bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  1544.  
  1545.     
  1546.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  1547. #if HDEBUG
  1548.     printf("socket\n");
  1549. #endif
  1550. #if HTS_WIDE_DEBUG    
  1551.     DEBUG_W("socket\n");
  1552. #endif
  1553.     soc=socket(AF_INET,SOCK_STREAM,0);
  1554. #if HTS_WIDE_DEBUG    
  1555.     DEBUG_W("socket done\n");
  1556. #endif
  1557.     if (soc==INVALID_SOCKET) {
  1558.       if (retour)
  1559.       if (retour->msg)
  1560.         strcpy(retour->msg,"Unable to create a socket");
  1561.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  1562.     }
  1563.     // structure: connexion au domaine internet, port 80 (ou autre)
  1564.     server.sin_family = AF_INET;
  1565.     server.sin_port = htons((unsigned short int) port);
  1566. #if HDEBUG
  1567.     printf("==%d\n",soc);
  1568. #endif
  1569.  
  1570.     // connexion non bloquante?
  1571.     if (!waitconnect ) {
  1572.       unsigned long p=1;  // non bloquant
  1573. #if HTS_WIN
  1574.       ioctlsocket(soc,FIONBIO,&p);
  1575. #else
  1576.       ioctl(soc,FIONBIO,&p);
  1577. #endif
  1578.     }
  1579.     
  1580.     // Connexion au serveur lui mΩme
  1581. #if HDEBUG
  1582.     printf("connect\n");
  1583. #endif
  1584.     
  1585. #if HTS_WIDE_DEBUG
  1586.     DEBUG_W("connect\n");
  1587. #endif
  1588. #if HTS_WIN
  1589.     if (connect(soc, (const struct sockaddr FAR *)&server, sizeof(server)) != 0) {
  1590. #else
  1591.       if (connect(soc, (struct sockaddr *)&server, sizeof(server)) == -1) {
  1592. #endif
  1593.         // bloquant
  1594.         if (waitconnect) {
  1595. #if HDEBUG
  1596.           printf("unable to connect!\n");
  1597. #endif
  1598.           if (retour)
  1599.           if (retour->msg)
  1600.             strcpy(retour->msg,"Unable to connect to the server");
  1601.           deletesoc(soc);
  1602.           return INVALID_SOCKET;
  1603.         }
  1604.       }
  1605. #if HTS_WIDE_DEBUG    
  1606.       DEBUG_W("connect done\n");
  1607. #endif
  1608.       
  1609. #if HDEBUG
  1610.       printf("connexion Θtablie\n");
  1611. #endif
  1612.     
  1613.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  1614.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  1615.     // read(soc,adr,taille)
  1616.  
  1617.   } else {    // on doit ouvrir un fichier local!
  1618.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  1619.  
  1620.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  1621.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  1622.  
  1623.   }   // teste fichier local ou http
  1624.   
  1625.   return soc;
  1626. }
  1627.  
  1628.  
  1629.  
  1630. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  1631. // retour=-1 si erreur.
  1632. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  1633. int ident_url(char* url,char* adr,char* fil) {
  1634.   char *p,*q;
  1635.   // traiter url
  1636.  
  1637.   // effacer adr et fil
  1638.   adr[0]=fil[0]='\0';
  1639.   
  1640.   p=strstr(url,"://");    // "scheme":// (RFC1945)
  1641.   if (p) {
  1642. #if HDEBUG
  1643.     printf("protocol: %s\n",url);
  1644. #endif
  1645.     // analyser le scheme
  1646.     if (strfield(url,"mailto")!=0) {
  1647.       return -1;    // erreur non reconnu
  1648.     } else if (strfield(url,"news")!=0) {
  1649.       return -1;    // erreur non reconnu
  1650.     } else if (strfield(url,"javascript")!=0) {
  1651.       return -1;    // erreur non reconnu
  1652.     //
  1653.     } else if (strfield(url,"file")!=0) {    // fichier local!! (pour les tests)
  1654.       p+=3;
  1655.       strcpy(adr,"file://");
  1656.       //## strcpy(adr,lOCAL_CHAR_STR);    // indique un fichier local..
  1657.     //
  1658.     } else if (strfield(url,"http")!=0) {    // HTTP
  1659.       p+=3;
  1660.     //
  1661.     } else if (strfield(url,"ftp")!=0) {    // FTP
  1662.       //if (ftp_available()) {
  1663.       strcpy(adr,"ftp://");    // FTP!!
  1664.       //}
  1665.       p+=3;
  1666.     } else {
  1667.       // return -1;
  1668.       p+=3;    // tant pis, beaucoup de ftp acceptent des requΦtes http 
  1669.                // on peut tjs essayer!
  1670.     }
  1671.   } else {
  1672.     int n;
  1673.     p=url;    // sans http://
  1674.     /* Bogus form: 
  1675.        "http:foo.html" means "foo.html" */
  1676.     if ((n=strfield(url,"http:")) !=0 ) {
  1677.       p+=n;
  1678.     }
  1679.   }
  1680.  
  1681.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  1682.   if (strcmp(adr,"file://")) {      // PAS file://
  1683.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  1684.     q=strchr(jump_identification(p),'/');
  1685.     if (q==0) q=p+strlen(p);  // pointe sur \0
  1686.     // pointe sur le chemin, ex: index.html?query=recherche
  1687.     
  1688.     // chemin www... trop long!!
  1689.     if ( ( ((int) q)- ((int) p) )  > HTS_URLMAXSIZE) {
  1690.       //strcpy(retour.msg,"Path too long");
  1691.       return -1;    // erreur
  1692.     }
  1693.     
  1694.     // recopier adresse www..
  1695.     strncat(adr,p, ((int) q) - ((int) p) );
  1696.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  1697.     // recopier chemin /pub/..
  1698.     strcat(fil,q);
  1699.     if (strnotempty(fil)==0)    // page par dΘfaut (/)
  1700.       strcat(fil,"/");
  1701.     // SECURITE:
  1702.     // simplifier url pour les ../
  1703.     fil_simplifie(fil);
  1704.   } else {    // localhost file://
  1705.     int i;
  1706.     char* a;
  1707.     strcat(fil,p);    // fichier local ; adr="#"
  1708.     a=strchr(fil,'?');
  1709.     if (a) 
  1710.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  1711.     // filtrer les \\ -> / pour les fichiers DOS
  1712.     for(i=0;i<(int) strlen(fil);i++)
  1713.       if (fil[i]=='\\')
  1714.         fil[i]='/';
  1715.   }
  1716.  
  1717.   // nommer au besoin.. (non utilisΘ normalement)
  1718.   if (strnotempty(fil)==0)
  1719.     strcpy(fil,"default-index.html");
  1720.  
  1721.   // case insensitive pour adresse
  1722.   {
  1723.     char *a=jump_identification(adr);
  1724.     while(*a) {
  1725.       if ((*a>='A') && (*a<='Z'))
  1726.         *a+='a'-'A';       
  1727.       a++;
  1728.     }
  1729.   }
  1730.   
  1731.   return 0;
  1732. }
  1733.  
  1734. // simplification des ../
  1735. void fil_simplifie(char* f) {
  1736.   int i=0;
  1737.   int last=0;
  1738.   char* a;
  1739.  
  1740.   // Θliminer ../
  1741.   while (f[i]) {
  1742.     
  1743.     if (f[i]=='/') {
  1744.       if (f[i+1]=='.')
  1745.       if (f[i+2]=='.')      // couper dernier rΘpertoire
  1746.       if (f[i+3]=='/')      // Θviter les /tmp/..coolandlamedir/
  1747.       {    // couper dernier rΘpertoire
  1748.         char tempo[HTS_URLMAXSIZE*2];
  1749.         tempo[0]='\0';
  1750.         //
  1751.         if (!last)                /* can't go upper.. */
  1752.           strcpy(tempo,"/");
  1753.         else
  1754.           strncpy(tempo,f,last+1);
  1755.         tempo[last+1]='\0';
  1756.         strcat(tempo,f+i+4);
  1757.         strcpy(f,tempo);    // remplacer
  1758.         i=-1;             // recommencer
  1759.         last=0;
  1760.       }
  1761.       
  1762.       if (i>=0)
  1763.         last=i;
  1764.       else
  1765.         last=0;
  1766.     }
  1767.     
  1768.     i++;
  1769.   }
  1770.  
  1771.   // Θliminer ./
  1772.   while ( (a=strstr(f,"./")) ) {
  1773.     char tempo[HTS_URLMAXSIZE*2];
  1774.     tempo[0]='\0';
  1775.     strcpy(tempo,a+2);
  1776.     strcpy(a,tempo);
  1777.   }
  1778.   // delete all remaining ../ (potential threat)
  1779.   while ( (a=strstr(f,"../")) ) {
  1780.     char tempo[HTS_URLMAXSIZE*2];
  1781.     tempo[0]='\0';
  1782.     strcpy(tempo,a+3);
  1783.     strcpy(a,tempo);
  1784.   }
  1785.   
  1786. }
  1787.  
  1788.  
  1789. // fermer liaison fichier ou socket
  1790. HTS_INLINE void deletehttp(htsblk* r) {
  1791. #if HTS_DEBUG_CLOSESOCK
  1792.     char info[256];
  1793.     sprintf(info,"deletehttp: (htsblk*) %d\n",r);
  1794.     DEBUG_W2(info);
  1795. #endif
  1796.   if (r->soc!=INVALID_SOCKET) {
  1797.     if (r->is_file) {
  1798.       if (r->fp)
  1799.         fclose(r->fp);
  1800.       r->fp=NULL;
  1801.     } else {
  1802.       if (r->soc!=LOCAL_SOCKET_ID)
  1803.         deletesoc(r->soc);
  1804.     }
  1805.     r->soc=INVALID_SOCKET;
  1806.   }
  1807. }
  1808.  
  1809. // fermer une socket
  1810. HTS_INLINE void deletesoc(T_SOC soc) {
  1811.   if (soc!=INVALID_SOCKET) {
  1812. // J'ai plantΘ.. pas de shutdown
  1813. //#if HTS_WIDE_DEBUG    
  1814. //    DEBUG_W("shutdown\n");
  1815. //#endif
  1816. //    shutdown(soc,2);  // shutdown
  1817. //#if HTS_WIDE_DEBUG    
  1818. //    DEBUG_W("shutdown done\n");
  1819. //#endif
  1820.     // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
  1821. #if HTS_WIDE_DEBUG    
  1822.     DEBUG_W("close\n");
  1823. #endif
  1824. #if HTS_WIN
  1825.     closesocket(soc);
  1826. #else
  1827.     close(soc);
  1828. #endif
  1829. #if HTS_WIDE_DEBUG    
  1830.     DEBUG_W("close done\n");
  1831. #endif
  1832.   }
  1833. }
  1834.  
  1835. // renvoi le nombre de secondes depuis 1970
  1836. HTS_INLINE double time_local() {
  1837.   return ((double) time(NULL));
  1838. }
  1839.  
  1840. // number of millisec since 1970
  1841. HTS_INLINE double mtime_local() {
  1842. #ifndef HTS_DO_NOT_USE_FTIME
  1843.   struct timeb B;
  1844.   ftime( &B );
  1845.   return (double) ( ((double) B.time * (double) 1000.0)
  1846.         + ((double) B.millitm) );
  1847. #else
  1848.   // not precise..
  1849.   return (double) ( ((double) time_local() * (double) 1000.0)
  1850.         + ((double) 0) );
  1851. #endif
  1852. }
  1853.  
  1854. // convertit un nombre de secondes en temps (chaine)
  1855. void sec2str(char *st,double t) {
  1856.   int j,h,m,s;
  1857.   
  1858.   j=(int) (t/(3600.0*24.0));
  1859.   t-=((double) j)*(3600.0*24.0);
  1860.   h=(int) (t/(3600.0));
  1861.   t-=((double) h)*3600.0;
  1862.   m=(int) (t/60.0);
  1863.   t-=((double) m)*60.0;
  1864.   s=(int) t;
  1865.   
  1866.   if (j>0)
  1867.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  1868.   else if (h>0)
  1869.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  1870.   else if (m>0)
  1871.     sprintf(st,"%d minutes %d seconds",m,s);
  1872.   else
  1873.     sprintf(st,"%d seconds",s);
  1874. }
  1875.  
  1876. // idem, plus court (chaine)
  1877. void qsec2str(char *st,double t) {
  1878.   int j,h,m,s;
  1879.   
  1880.   j=(int) (t/(3600.0*24.0));
  1881.   t-=((double) j)*(3600.0*24.0);
  1882.   h=(int) (t/(3600.0));
  1883.   t-=((double) h)*3600.0;
  1884.   m=(int) (t/60.0);
  1885.   t-=((double) m)*60.0;
  1886.   s=(int) t;
  1887.   
  1888.   if (j>0)
  1889.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  1890.   else if (h>0)
  1891.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  1892.   else if (m>0)
  1893.     sprintf(st,"%dmin%02ds",m,s);
  1894.   else
  1895.     sprintf(st,"%ds",s);
  1896. }
  1897.  
  1898.  
  1899. // heure actuelle, GMT, format rfc (taille buffer 256o)
  1900. void time_gmt_rfc822(char* s) {
  1901.   time_t tt;
  1902.   struct tm* A;
  1903.   tt=time(NULL);
  1904.   A=gmtime(&tt);
  1905.   if (A==NULL)
  1906.     A=localtime(&tt);
  1907.   time_rfc822(s,A);
  1908. }
  1909.  
  1910. // heure actuelle, format rfc (taille buffer 256o)
  1911. void time_local_rfc822(char* s) {
  1912.   time_t tt;
  1913.   struct tm* A;
  1914.   tt=time(NULL);
  1915.   A=localtime(&tt);
  1916.   time_rfc822_local(s,A);
  1917. }
  1918.  
  1919. /* convertir une chaine en temps */
  1920. struct tm* convert_time_rfc822(char* s) {
  1921.   static struct tm result;
  1922.   /* */
  1923.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  1924.   char str[256];
  1925.   char* a;
  1926.   /* */
  1927.   int result_mm=-1;
  1928.   int result_dd=-1;
  1929.   int result_n1=-1;
  1930.   int result_n2=-1;
  1931.   int result_n3=-1;
  1932.   int result_n4=-1;
  1933.   /* */
  1934.   if ((int) strlen(s) > 200)
  1935.     return NULL;
  1936.   strcpy(str,s);
  1937.   hts_lowcase(str);
  1938.   /* Θliminer :,- */
  1939.   while( (a=strchr(str,'-')) ) *a=' ';
  1940.   while( (a=strchr(str,':')) ) *a=' ';
  1941.   while( (a=strchr(str,',')) ) *a=' ';
  1942.   /* tokeniser */
  1943.   a=str;
  1944.   while(*a) {
  1945.     char *first,*last;
  1946.     char tok[256];
  1947.     /* dΘcouper mot */
  1948.     while(*a==' ') a++;   /* sauter espaces */
  1949.     first=a;
  1950.     while((*a) && (*a!=' ')) a++;
  1951.     last=a;
  1952.     tok[0]='\0';
  1953.     if (first!=last) {
  1954.       char* pos;
  1955.       strncat(tok,first,(int) last-(int) first);
  1956.       /* analyser */
  1957.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  1958.         result_mm=((int) pos-(int) months)/4;
  1959.       } else {
  1960.         int number;
  1961.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  1962.           if (result_dd<0)                        /* day always first number */
  1963.             result_dd=number;
  1964.           else if (result_n1<0)
  1965.             result_n1=number;
  1966.           else if (result_n2<0)
  1967.             result_n2=number;
  1968.           else if (result_n3<0)
  1969.             result_n3=number;
  1970.           else if (result_n4<0)
  1971.             result_n4=number;
  1972.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  1973.       }
  1974.     }
  1975.   }
  1976.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  1977.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  1978.       result.tm_year=result_n4-1900;
  1979.       result.tm_hour=result_n1;
  1980.       result.tm_min=result_n2;
  1981.       result.tm_sec=max(result_n3,0);
  1982.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  1983.       result.tm_hour=result_n2;
  1984.       result.tm_min=result_n3;
  1985.       result.tm_sec=max(result_n4,0);
  1986.       if (result_n1<=50)                /* 00 means 2000 */
  1987.         result.tm_year=result_n1+100;
  1988.       else if (result_n1<1000)          /* 99 means 1999 */
  1989.         result.tm_year=result_n1;
  1990.       else                              /* 2000 */
  1991.         result.tm_year=result_n1-1900;
  1992.     }
  1993.     result.tm_isdst=0;        /* assume GMT */
  1994.     result.tm_yday=-1;        /* don't know */
  1995.     result.tm_wday=-1;        /* don't know */
  1996.     result.tm_mon=result_mm;
  1997.     result.tm_mday=result_dd;
  1998.     return &result;
  1999.   }
  2000.   return NULL;
  2001. }
  2002.  
  2003. /* sets file time. -1 if error */
  2004. int set_filetime(char* file,struct tm* tm_time) {
  2005.   struct utimbuf tim;
  2006. #ifndef HTS_DO_NOT_USE_FTIME
  2007.   struct timeb B;
  2008.   B.timezone=0;
  2009.   ftime( &B );
  2010.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  2011. #else
  2012.   // bogus time (GMT/local)..
  2013.   tim.actime=tim.modtime=mktime(tm_time); 
  2014. #endif
  2015.   return utime(file,&tim);
  2016. }
  2017.  
  2018. /* sets file time from RFC822 date+time, -1 if error*/
  2019. int set_filetime_rfc822(char* file,char* date) {
  2020.   struct tm* tm_s=convert_time_rfc822(date);
  2021.   if (tm_s) {
  2022.     return set_filetime(file,tm_s);
  2023.   } else return -1;
  2024. }
  2025.  
  2026.  
  2027. // heure au format rfc (taille buffer 256o)
  2028. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2029.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2030. }
  2031.  
  2032. // heure locale au format rfc (taille buffer 256o)
  2033. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2034.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2035. }
  2036.  
  2037. // conversion en b,Kb,Mb
  2038. char* int2bytes(LLint n) {
  2039.   static char buff[256];
  2040.   char** a=int2bytes2(n);
  2041.   strcpy(buff,a[0]);
  2042.   strcat(buff,a[1]);
  2043.   return buff;
  2044. }
  2045.  
  2046. // conversion en b/s,Kb/s,Mb/s
  2047. char* int2bytessec(long int n) {
  2048.   static char buff[256];
  2049.   char** a=int2bytes2(n);
  2050.   strcpy(buff,a[0]);
  2051.   strcat(buff,a[1]);
  2052.   return concat(buff,"/s");
  2053. }
  2054.  
  2055. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2056. // limite: 2.10^9.10^6B
  2057. char** int2bytes2(LLint n) {
  2058.   static char buff1[256];
  2059.   static char buff2[32];
  2060.   static char* buffadr[2];
  2061.   if (n<1024) {
  2062.     sprintf(buff1,"%d",(int)(LLint)n);
  2063.     strcpy(buff2,"B");
  2064.   } else if (n < (LLint)(1024*1024)) {
  2065.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/1024),(int)(LLint)((n%1024)*100)/1024);
  2066.     strcpy(buff2,"KB");
  2067.   }
  2068. #ifdef HTS_LONGLONG
  2069.   else if (n < (LLint)(1024*1024*1024)) {
  2070.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/(1024*1024)),(int)(LLint)(((n%(1024*1024))*100)/(1024*1024)));
  2071.     strcpy(buff2,"MB");
  2072.   } else {
  2073.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/(1024*1024*1024)),(int)(LLint)(((n%(1024*1024*1024))*100)/(1024*1024*1024)));
  2074.     strcpy(buff2,"GB");
  2075.   }
  2076. #else
  2077.   else {
  2078.     sprintf(buff1,"%d,%02d",(int)(LLint)(n/(1024*1024)),(int)(LLint)(((n%(1024*1024))*100)/(1024*1024)));
  2079.     strcpy(buff2,"MB");
  2080.   }
  2081. #endif
  2082.   buffadr[0]=buff1;
  2083.   buffadr[1]=buff2;
  2084.   return buffadr;
  2085. }
  2086.  
  2087.  
  2088. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2089. HTS_INLINE int sendc(T_SOC soc,char* s) {
  2090. #if HDEBUG
  2091.   write(0,s,strlen(s));
  2092. #endif
  2093. //#if HTS_WIN
  2094.   return send(soc,s,strlen(s),0);
  2095. //#else
  2096. //  return write(soc,s,strlen(s));
  2097. //#endif
  2098. }
  2099.  
  2100.  
  2101. // Remplace read
  2102. void finput(int fd,char* s,int max) {
  2103.   static char c;
  2104.   register int j=0;
  2105.   do {
  2106.     //c=fgetc(fp);
  2107.     if (read(fd,&c,1)<=0) {
  2108.       c=0;
  2109.     }
  2110.     if (c!=0) {
  2111.       switch(c) {
  2112.       case 10: c=0; break;
  2113.       case 13: break;  // sauter ces caractΦres
  2114.       default: s[j++]=c; break;
  2115.       }
  2116.     }
  2117.   }  while((c!=0) && (j<max-1));
  2118.   s[j++]='\0';
  2119.  
  2120. // lire ligne dans buffer, renvoi incrΘment α opΘrer sur l'adresse ensuite
  2121. int binput(char* buff,char* s,int max) {
  2122.   static char c;
  2123.   register int j=0;
  2124.   register int i=0;
  2125.   if ((*buff)=='\0') {  // fin du buffer
  2126.     s[0]='\0';
  2127.     return 0;  // eof  
  2128.   }
  2129.   do {
  2130.     //c=fgetc(fp);
  2131.     c=*(buff++); i++;
  2132.     if (c!=0) {
  2133.       switch(c) {
  2134.       case 10: c=0; break;
  2135.       case 13: break;  // sauter ces caractΦres
  2136.       default: s[j++]=c; break;
  2137.       }
  2138.     }
  2139.   }  while((c!=0) && (j<max-1));
  2140.   s[j++]='\0';
  2141.   return i;
  2142.  
  2143. // Remplace fscanf(fp,"%s",s)
  2144. void linput(FILE* fp,char* s,int max) {
  2145.   register int c;
  2146.   register int j=0;
  2147.   do {
  2148.     c=fgetc(fp);
  2149.     if (c!=EOF) {
  2150.       switch(c) {
  2151.         case 13: break;  // sauter CR
  2152.         case 10: c=-1; break;
  2153.         case 9: case 12: break;  // sauter ces caractΦres
  2154.         default: s[j++]=(char) c; break;
  2155.       }
  2156.     }
  2157.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2158.   s[j++]='\0';
  2159. }
  2160. void linput_trim(FILE* fp,char* s,int max) {
  2161.   char* ls=(char*) malloc(max+2);
  2162.   if (ls) {
  2163.     char* a;
  2164.     // lire ligne
  2165.     linput(fp,ls,max);
  2166.     // sauter espaces et tabs en fin
  2167.     while((ls[strlen(ls)-1]==' ') || (ls[strlen(ls)-1]=='\t')) ls[strlen(ls)-1]='\0';
  2168.     // sauter espaces en dΘbut
  2169.     a=ls; while((*a==' ') || (*a=='\t')) a++;
  2170.     strcpy(s,a);
  2171.     //
  2172.     free(ls);
  2173.   }
  2174. }
  2175. void linput_cpp(FILE* fp,char* s,int max) {
  2176.   s[0]='\0';
  2177.   do {
  2178.     if (s[strlen(s)-1]=='\\') s[strlen(s)-1]='\0';      // couper \ final
  2179.     // lire ligne
  2180.     linput_trim(fp,s+strlen(s),max-strlen(s));
  2181.   } while((s[strlen(s)-1]=='\\') && ((int)strlen(s)<max));
  2182. }
  2183.  
  2184. // idem avec les car spΘciaux
  2185. void rawlinput(FILE* fp,char* s,int max) {
  2186.   register int c;
  2187.   register int j=0;
  2188.   do {
  2189.     c=fgetc(fp);
  2190.     if (c!=EOF) {
  2191.       switch(c) {
  2192.         case 13: break;  // sauter CR
  2193.         case 10: c=-1; break;
  2194.         default: s[j++]=(char) c; break;
  2195.       }
  2196.     }
  2197.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2198.   s[j++]='\0';
  2199. }
  2200.  
  2201.  
  2202. // compare le dΘbut de f avec s et retourne la position de la fin
  2203. // 'A=a' (case insensitive)
  2204. int strfield(const char* f,const char* s) {
  2205.   register int r=0;
  2206.   while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
  2207.   if (*s==0)
  2208.     return r;
  2209.   else
  2210.     return 0;
  2211. }
  2212.  
  2213. //cherche chaine, case insensitive
  2214. char* strstrcase(char *s,char *o) {
  2215.   while((*s) && (strfield(s,o)==0)) s++;
  2216.   if (*s=='\0') return NULL;
  2217.   return s;  
  2218. }
  2219.  
  2220.  
  2221. // le fichier est-il un fichier html?
  2222. //  0 : non
  2223. //  1 : oui
  2224. // -1 : on sait pas
  2225. // -2 : on sait pas, pas d'extension
  2226. int ishtml(char* fil) {
  2227.   char *a;
  2228.  
  2229.   // patch pour les truc.html?Choix=toto
  2230.   if ( (a=strchr(fil,'?')) )  // paramΦtres?
  2231.     a--;  // pointer juste avant le ?
  2232.   else
  2233.     a=fil+strlen(fil)-1;  // pointer sur le dernier caractΦre
  2234.  
  2235.   if (*a=='/') return -1;    // rΘpertoire, on sait pas!!
  2236.   //if (*a=='/') return 1;    // ok rΘpertoire, html
  2237.  
  2238.   while ( (*a!='.') && (*a!='/')  && ((int) a>(int) fil)) a--;
  2239.   if (*a=='.') {  // a une extension
  2240.     a++;  // pointer sur extension
  2241.     return ishtml_ext(a);     // retour
  2242.   } else return -2;   // indΘterminΘ, par exemple /truc
  2243. }
  2244.  
  2245. // idem, mais pour uniquement l'extension
  2246. int ishtml_ext(char* a) {
  2247.   int html=0;  
  2248.   //
  2249.   if (strfield2(a,"html"))  html = 1;
  2250.   else if (strfield2(a,"htm"))   html = 1;
  2251.   else if (strfield2(a,"shtml")) html = 1;
  2252.   else if (strfield2(a,"htmlx")) html = 1;
  2253.   else if (strfield2(a,"shtm"))  html = 1;
  2254.   else if (strfield2(a,"htmx"))  html = 1;
  2255.   //
  2256.   else if (strfield2(a,"asp"))   html = -1;
  2257.   else if (strfield2(a,"cgi"))   html = -1;    // indΘterminΘ
  2258.   //
  2259.   // insuccΦs..
  2260.   else {
  2261.     if (is_knowntype(a))
  2262.       html = 0;     // connu, non html (html ont ΘtΘ testΘs avant)
  2263.     else
  2264.       html = -1;    // inconnu..
  2265.   }
  2266.   return html;  
  2267. }
  2268.  
  2269. // error (404,500..)
  2270. HTS_INLINE int ishttperror(int err) {
  2271.   switch (err/100) {
  2272.     case 4: case 5: return 1;
  2273.       break;
  2274.   }
  2275.   return 0;
  2276. }
  2277.  
  2278.  
  2279. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant une identification
  2280. char* jump_identification(char* source) {
  2281.   char *a,*b;
  2282.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  2283.   // mais sauter ftp:// Θventuel
  2284.   a = jump_protocol(source);
  2285.   while( (b = strchr(a,'@')) ) {
  2286.     char* c;
  2287.     if ( (c=strchr(a,'/')) )        /* si un / est trouvΘ */
  2288.     if ((int) c < (int) b)      /* avant le @ */
  2289.       return a;                 /* alors exit (http://www.foo.bar/1.html@A20) */
  2290.     a=b+1;
  2291.   }
  2292.   return a;
  2293. }
  2294.  
  2295. // retourner adr sans ftp://
  2296. HTS_INLINE char* jump_protocol(char* source) {
  2297.   if (strncmp(source,"ftp://",6)==0)
  2298.     return source+6;
  2299.   else if (strncmp(source,"http://",7)==0)
  2300.     return source+7;
  2301.   /* bogus form: http:relative.html */
  2302.   else if (strncmp(source,"http:",5)==0)
  2303.     return source+5;
  2304.   return source;
  2305. }
  2306.  
  2307. // codage base 64 a vers b
  2308. void code64(char* a,char* b) {
  2309.   int i1=0,i2=0,i3=0,i4=0;
  2310.   unsigned long store;
  2311.   int n;
  2312.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2313.   b[0]='\0';
  2314.   while(*a) {  
  2315.     // 24 bits
  2316.     n=1; store=0; store |= ((*a++) & 0xff);
  2317.     if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); }
  2318.     if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); }
  2319.     if (n==3) {
  2320.       i4=store & 63;
  2321.       i3=(store>>6) & 63;
  2322.       i2=(store>>12) & 63;
  2323.       i1=(store>>18) & 63;
  2324.     } else if (n==2) {
  2325.       store<<=2;    
  2326.       i3=store & 63;
  2327.       i2=(store>>6) & 63;
  2328.       i1=(store>>12) & 63;
  2329.     } else {
  2330.       store<<=4;
  2331.       i2=store & 63;
  2332.       i1=(store>>6) & 63;
  2333.     }
  2334.     
  2335.     *b++ = _hts_base64[i1];
  2336.     *b++ = _hts_base64[i2];
  2337.     if (n>=2)
  2338.       *b++ = _hts_base64[i3];
  2339.     else
  2340.       *b++ = '=';
  2341.     if (n>=3)
  2342.       *b++ = _hts_base64[i4];
  2343.     else
  2344.       *b++ = '=';
  2345.   }
  2346.   *b++='\0';
  2347. }
  2348.  
  2349. // remplacer " par " etc..
  2350. // buffer MAX 1Ko
  2351. void unescape_amp(char* s) {
  2352.   while(*s) {
  2353.     if (*s=='&') {
  2354.       char* end=strchr(s,';');
  2355.       if ( ((int) end - (int) s) <= 8) {
  2356.         char c=0;
  2357.         if (strfield(s,"&"))
  2358.           c='&';
  2359.         else if (strfield(s,"°"))
  2360.           c='░';
  2361.         else if (strfield(s,">"))
  2362.           c='>';
  2363.         else if (strfield(s,"«"))
  2364.           c='\"';
  2365.         else if (strfield(s,"<"))
  2366.           c='<';
  2367.         else if (strfield(s," "))
  2368.           c=' ';
  2369.         else if (strfield(s,"""))
  2370.           c='\"';
  2371.         else if (strfield(s,"»"))
  2372.           c='\"';
  2373.         else if (strfield(s,"­"))
  2374.           c='-';
  2375.         else if (strfield(s,"˜"))
  2376.           c='~';
  2377.         else if (strfield(s,"&"))
  2378.           c='&';
  2379.         // remplacer?
  2380.         if (c) {
  2381.           char buff[HTS_URLMAXSIZE*2];
  2382.           buff[0]=c;
  2383.           strcpy(buff+1,end+1);
  2384.           strcpy(s,buff);
  2385.         }
  2386.       }
  2387.     }
  2388.     s++;
  2389.   }
  2390. }
  2391.  
  2392. // remplacer %20 par ' ', | par : etc..
  2393. // buffer MAX 1Ko
  2394. char* unescape_http(char* s) {
  2395.   static char tempo[HTS_URLMAXSIZE*2];
  2396.   int i,j=0;
  2397.   for (i=0;i<(int) strlen(s);i++) {
  2398.     if (s[i]=='%') {
  2399.       i++;
  2400.       tempo[j++]=(char) ehex(s+i);
  2401.       i++;    // sauter 2 caractΦres finalement
  2402.     }
  2403.     /*
  2404.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  2405.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2406.       tempo[j++]=':';
  2407.     }
  2408.     */
  2409.     else
  2410.       tempo[j++]=s[i];
  2411.   }
  2412.   tempo[j++]='\0';
  2413.   return tempo;
  2414. }
  2415.  
  2416. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  2417. char* unescape_http_unharm(char* s) {
  2418.   static char tempo[HTS_URLMAXSIZE*2];
  2419.   int i,j=0;
  2420.   for (i=0;i<(int) strlen(s);i++) {
  2421.     if (s[i]=='%') {
  2422.       int nchar=(char) ehex(s+i+1);
  2423.  
  2424.       int test = (  CHAR_RESERVED(nchar)
  2425.                 || CHAR_DELIM(nchar)
  2426.                 || CHAR_UNWISE(nchar)
  2427.                 || CHAR_SPECIAL(nchar)
  2428.                 || CHAR_XXAVOID(nchar) );
  2429.  
  2430.       if (!test) {
  2431.         tempo[j++]=(char) ehex(s+i+1);
  2432.         i+=2;
  2433.       } else {
  2434.         tempo[j++]='%';
  2435.       }
  2436.     }
  2437.     /*
  2438.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  2439.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2440.       tempo[j++]=':';
  2441.     }
  2442.     */
  2443.     else
  2444.       tempo[j++]=s[i];
  2445.   }
  2446.   tempo[j++]='\0';
  2447.   return tempo;
  2448. }
  2449.  
  2450. // remplacer " par %xx etc..
  2451. // buffer MAX 1Ko
  2452. void escape_spc_url(char* s) {
  2453.   x_escape_http(s,2);
  2454. }
  2455. // smith / john -> smith%20%2f%20john
  2456. void escape_in_url(char* s) {
  2457.   x_escape_http(s,1);
  2458. }
  2459. void escape_check_url(char* s) {
  2460.   x_escape_http(s,0);
  2461. }
  2462. void x_escape_http(char* s,int mode) {
  2463.   while(*s) {
  2464.     int test=0;
  2465.     if (mode == 0)
  2466.       test=(strchr("\" ",*s)!=0);
  2467.     else if (mode==1) {
  2468.       test = (  CHAR_RESERVED(*s)
  2469.              || CHAR_DELIM(*s)
  2470.              || CHAR_UNWISE(*s)
  2471.              || CHAR_SPECIAL(*s)
  2472.              || CHAR_XXAVOID(*s) );
  2473.     }
  2474.     else if (mode==2)
  2475.       test=(strchr(" ",*s)!=0);           // n'escaper que espace
  2476.  
  2477.     if (test) {
  2478.       char buffer[HTS_URLMAXSIZE*2];
  2479.       int n;
  2480.       n=(int)(unsigned char) *s;
  2481.       strcpy(buffer,s+1);
  2482.       sprintf(s,"%%%02x",n);
  2483.       strcat(s,buffer);
  2484.     }
  2485.     s++;
  2486.   }
  2487. }
  2488.  
  2489.  
  2490. HTS_INLINE int ehexh(char c) {
  2491.   if ((c>='0') && (c<='9')) return c-'0';
  2492.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  2493.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  2494.   return 0;
  2495. }
  2496.  
  2497. HTS_INLINE int ehex(char* s) {
  2498.   return 16*ehexh(*s)+ehexh(*(s+1));
  2499.  
  2500. }
  2501.  
  2502. // concat, concatΦne deux chaines et renvoi le rΘsultat
  2503. // permet d'allΘger grandement le code
  2504. // il faut savoir qu'on ne peut mettre plus de 8 concat() dans une expression
  2505. char* concat(const char* a,const char* b) {
  2506.   static char buff[8][HTS_URLMAXSIZE*2];
  2507.   static int rol;
  2508.   rol=((rol+1)%8);    // roving pointer
  2509.   strcpy(buff[rol],a);
  2510.   if (b) strcat(buff[rol],b);
  2511.   return buff[rol];
  2512. }
  2513. // conversion fichier / -> antislash
  2514. #if HTS_DOSNAME
  2515. char* __fconv(char* a) {
  2516.   int i;
  2517.   for(i=0;i<(int) strlen(a);i++)
  2518.     if (a[i]=='/')  // convertir
  2519.       a[i]='\\';
  2520.   return a;
  2521. }
  2522. char* fconcat(char* a,char* b) {
  2523.   return __fconv(concat(a,b));
  2524. }
  2525. char* fconv(char* a) {
  2526.   return __fconv(concat(a,""));
  2527. }
  2528. #endif
  2529.  
  2530. /* / et \\ en / */
  2531. char* __fslash(char* a) {
  2532.   int i;
  2533.   for(i=0;i<(int) strlen(a);i++)
  2534.     if (a[i]=='\\')  // convertir
  2535.       a[i]='/';
  2536.   return a;
  2537. }
  2538. char* fslash(char* a) {
  2539.   return __fslash(concat(a,""));
  2540. }
  2541.  
  2542. // conversion minuscules, avec buffer
  2543. char* convtolower(char* a) {
  2544.   static char buff[8][HTS_URLMAXSIZE*2];
  2545.   static int rol;
  2546.   rol=((rol+1)%8);    // roving pointer
  2547.   strcpy(buff[rol],a);
  2548.   hts_lowcase(buff[rol]);  // lower case
  2549.   return buff[rol];
  2550. }
  2551.  
  2552. // conversion en minuscules
  2553. void hts_lowcase(char* s) {
  2554.   register int i;
  2555.   for(i=0;i<(int) strlen(s);i++)
  2556.     if ((s[i]>='A') && (s[i]<='Z'))
  2557.       s[i]+=('a'-'A');
  2558. }
  2559.  
  2560. // remplacer un caractΦre d'une chaεne dans une autre
  2561. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  2562.   register char* a;
  2563.   while ((a=strchr(s,from))!=NULL) {
  2564.     *a=to;
  2565.   }
  2566. }
  2567.  
  2568.  
  2569. // caractΦre espace, guillemets, CR, LF etc..
  2570. /* SECTION OPTIMISEE:
  2571.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  2572.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09",c)!=NULL)
  2573. */
  2574. /*
  2575. HTS_INLINE int is_space(char c) {
  2576.   if (c==' ')  return 1;  // spc
  2577.   if (c=='"')  return 1;  // quote
  2578.   if (c==10)   return 1;  // lf
  2579.   if (c==13)   return 1;  // cr
  2580.   if (c=='\'') return 1;  // quote
  2581.   //if (c=='`')  return 1;  // backquote      << non
  2582.   if (c==9)    return 1;  // tab
  2583.   return 0;
  2584. }
  2585. */
  2586.  
  2587. // caractΦre espace, CR, LF, TAB
  2588. /*
  2589. HTS_INLINE int is_realspace(char c) {
  2590.   if (c==' ')  return 1;  // spc
  2591.   if (c==10)   return 1;  // lf
  2592.   if (c==13)   return 1;  // cr
  2593.   if (c==9)    return 1;  // tab
  2594.   return 0;
  2595. }
  2596. */
  2597.  
  2598.  
  2599.  
  2600.  
  2601.  
  2602. // deviner type d'un fichier local..
  2603. // ex: fil="toto.gif" -> s="image/gif"
  2604. void guess_httptype(char *s,char *fil) {
  2605.   get_httptype(s,fil,1);
  2606. }
  2607. // idem
  2608. // flag: 1 si toujours renvoyer un type
  2609. void get_httptype(char *s,char *fil,int flag) {
  2610.   if (ishtml(fil)==1)
  2611.     strcpy(s,"text/html");
  2612.   else {
  2613.     char *a=fil+strlen(fil)-1;    
  2614.     while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  2615.     if (*a=='.') {
  2616.       int ok=0;
  2617.       int j=0;
  2618.       a++;
  2619.       while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  2620.         if (strfield2(hts_mime[j][1],a)) {
  2621.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  2622.             strcpy(s,hts_mime[j][0]);
  2623.             ok=1;
  2624.           }
  2625.         }
  2626.         j++;
  2627.       }
  2628.       
  2629.       if (!ok) if (flag) sprintf(s,"application/%s",a);
  2630.     } else {
  2631.       if (flag) strcpy(s,"application/octet-stream");
  2632.     }
  2633.   }
  2634. }
  2635. // renvoyer extesion d'un type mime..
  2636. // ex: "image/gif" -> gif
  2637. void give_mimext(char *s,char *st) {   
  2638.   int ok=0;
  2639.   int j=0;
  2640.   strcpy(s,"");
  2641.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  2642.     if (strfield2(hts_mime[j][0],st)) {
  2643.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  2644.         strcpy(s,hts_mime[j][1]);
  2645.         ok=1;
  2646.       }
  2647.     }
  2648.     j++;
  2649.   }    
  2650. }
  2651. // extension connue?..
  2652. int is_knowntype(char *fil) {
  2653.   int j=0;
  2654.   if (!fil)
  2655.     return 0;
  2656.   while(strnotempty(hts_mime[j][1])) {
  2657.     if (strfield2(hts_mime[j][1],fil)) {
  2658.       return 1;
  2659.     }
  2660.     j++;
  2661.   }
  2662.   return 0;
  2663. }
  2664. // extension : html,gif..
  2665. char* get_ext(char *fil) {
  2666.   char *a=fil+strlen(fil)-1;    
  2667.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  2668.   if (*a=='.')
  2669.     return a+1;
  2670.   else
  2671.     return NULL;
  2672. }
  2673.  
  2674. // page dynamique?
  2675. // is_dyntype(get_ext("foo.asp"))
  2676. int is_dyntype(char *fil) {
  2677.   int j=0;
  2678.   if (!fil)
  2679.     return 0;
  2680.   while(strnotempty(hts_ext_dynamic[j])) {
  2681.     if (strfield2(hts_ext_dynamic[j],fil)) {
  2682.       return 1;
  2683.     }
  2684.     j++;
  2685.   }
  2686.   return 0;
  2687. }
  2688.  
  2689. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  2690. // connaissent pas le type
  2691. int may_unknown(char* st) {
  2692.   int j=0;
  2693.   // types mΘdia
  2694.   if (may_be_hypertext_mime(st))
  2695.     return 1;
  2696.   while(strnotempty(hts_mime_keep[j])) {
  2697.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  2698.       return 1;
  2699.     }
  2700.     j++;
  2701.   }    
  2702.   return 0;
  2703. }
  2704.  
  2705.  
  2706.  
  2707. // -- Utils fichiers
  2708. /* Le fichier existe-t-il? (ou est-il HTS_ACCESSible?) */
  2709. int fexist(char* s) {
  2710.   FILE* fp;
  2711.   if (strnotempty(s)==0)     // nom vide: non trouvΘ
  2712.     return 0;
  2713.   fp=fopen(fconv(s),"rb");
  2714.   if (fp!=NULL) fclose(fp);
  2715.   return (fp!=NULL);
  2716.  
  2717. /* Taille d'un fichier, -1 si n'existe pas */
  2718. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  2719. /* Note: NOT YET READY FOR 64-bit */
  2720. //LLint fsize(char* s) {
  2721. int fsize(char* s) {
  2722.   /*
  2723. #if HTS_WIN
  2724.   HANDLE hFile;
  2725.   DWORD dwSizeHigh = 0;
  2726.   DWORD dwSizeLow  = 0;
  2727.   hFile = CreateFile(s,0,0,NULL,OPEN_EXISTING,0,NULL);
  2728.   if (hFile) {
  2729.     dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;
  2730.     CloseHandle(hFile);
  2731.     if (dwSizeLow != 0xFFFFFFFF)
  2732.       return (dwSizeLow & (dwSizeHigh<<32));
  2733.     else
  2734.       return -1;
  2735.   } else
  2736.     return -1;
  2737. #else
  2738.     */
  2739.   FILE* fp;
  2740.   if (strnotempty(s)==0)     // nom vide: erreur
  2741.     return -1;
  2742.   fp=fopen(fconv(s),"rb");
  2743.   if (fp!=NULL) {
  2744.     int i;
  2745.     fseek(fp,0,SEEK_END);
  2746.     i=ftell(fp);
  2747.     fclose(fp);
  2748.     return i;
  2749.   } else return -1;
  2750.   /*
  2751. #endif
  2752.   */
  2753. }
  2754.  
  2755. int fpsize(FILE* fp) {
  2756.   int oldpos,size;
  2757.   if (!fp)
  2758.     return -1;
  2759.   oldpos=ftell(fp);
  2760.   fseek(fp,0,SEEK_END);
  2761.   size=ftell(fp);
  2762.   fseek(fp,oldpos,SEEK_SET);
  2763.   return size;
  2764. }
  2765.  
  2766.  
  2767. hts_stat_struct HTS_STAT;
  2768. //LLint HTS_TOTAL_RECV = 0;  // flux entrant reτu
  2769. //int HTS_TOTAL_RECV_STATE = 0;  // status: 0 tout va bien 1: ralentir un peu 2: ralentir 3: beaucoup
  2770. void HTS_TOTAL_RECV_CHECK(int var) {
  2771.   if (HTS_STAT.HTS_TOTAL_RECV_STATE) { 
  2772.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  2773.       var = min(var,32); 
  2774.       Sleep(250); 
  2775.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  2776.       var = min(var,256); 
  2777.       Sleep(100); 
  2778.     } else { 
  2779.       var/=2; 
  2780.       if (var<=0) var=1; 
  2781.       Sleep(50); 
  2782.     } 
  2783.   }
  2784. }
  2785.  
  2786. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  2787. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  2788.   register int retour;
  2789.   //  return read(soc,buff,size);
  2790.   if (r->is_file) {
  2791. #if HTS_WIDE_DEBUG    
  2792.     DEBUG_W("read\n");
  2793. #endif
  2794.     if (r->fp)
  2795.       retour=fread(buff,1,size,r->fp);
  2796.     else
  2797.       retour=-1;
  2798.   } else {
  2799. #if HTS_WIDE_DEBUG    
  2800.     DEBUG_W("recv\n");
  2801.     if (r->soc==INVALID_SOCKET)
  2802.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  2803. #endif
  2804.     HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  2805.     retour=recv(r->soc,buff,size,0);
  2806.     if (retour>0)    // compter flux entrant
  2807.       HTS_STAT.HTS_TOTAL_RECV+=retour;
  2808.   }
  2809. #if HTS_WIDE_DEBUG    
  2810.   DEBUG_W("recv/read done\n");
  2811. #endif
  2812.   return retour;
  2813. }
  2814.  
  2815.  
  2816. // -- Gestion cache DNS --
  2817. // 'RX98
  2818. #if HTS_DNSCACHE
  2819.  
  2820. // 'capsule' contenant uniquement le cache
  2821. t_dnscache* _hts_cache() {
  2822.   static t_dnscache cache;
  2823.   return &cache;
  2824. }
  2825.  
  2826. // lock le cache dns pour tout opΘration d'ajout
  2827. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  2828. // -1: status? 0: libΘrer 1:locker
  2829.  
  2830. /* 
  2831.   Simple lock function for cache
  2832.  
  2833.   Return value: always 0
  2834.   Parameter:
  2835.   1 wait for lock (mutex) available and lock it
  2836.   0 unlock the mutex
  2837.   [-1 check if locked (always return 0 with mutex)]
  2838.   -999 initialize
  2839. */
  2840. #if USE_BEGINTHREAD
  2841. int _hts_lockdns(int i) {
  2842.   static PTHREAD_LOCK_TYPE hMutex; 
  2843.   return htsSetLock(&hMutex,i);
  2844. }
  2845. #else
  2846. int _hts_lockdns(int i) {
  2847.   static int l=0;
  2848.   if (i>=0)
  2849.     l=i;
  2850.   return l;
  2851. }
  2852. #endif
  2853.  
  2854. // routine pour le cache - retour optionnel α donner α chaque fois
  2855. // NULL: nom non encore testΘ dans le cache
  2856. // si h_length==0 alors le nom n'existe pas dans le dns
  2857. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  2858.   // attendre que le cache dns soit prΩt
  2859.   while(_hts_lockdns(-1));  // attendre libΘration
  2860.   _hts_lockdns(1);          // locker
  2861.  
  2862.   while(1) {
  2863.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  2864.       if (cache->host_length>0) {  // entrΘe valide
  2865.         if (retour->h_addr)
  2866.           bcopy(cache->host_addr,(char *)retour->h_addr,cache->host_length);
  2867.         retour->h_length=cache->host_length;
  2868.       } else if (cache->host_length==0) {  // en cours
  2869.         _hts_lockdns(0);          // dΘlocker
  2870.         return NULL;
  2871.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  2872.         if (retour->h_addr)
  2873.           retour->h_addr[0]='\0';
  2874.         retour->h_length=0;  // erreur, n'existe pas
  2875.       }
  2876.       _hts_lockdns(0);          // dΘlocker
  2877.       return retour;
  2878.     } else {    // on a pas encore trouvΘ
  2879.       if (cache->n!=NULL) { // chercher encore
  2880.         cache=cache->n;   // suivant!
  2881.       } else {
  2882.         _hts_lockdns(0);          // dΘlocker
  2883.         return NULL;    // non prΘsent        
  2884.       }
  2885.     }    
  2886.   }
  2887. }
  2888.  
  2889. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  2890. // 0 non encore
  2891. // 1 ok
  2892. // 2 non prΘsent
  2893. int hts_dnstest(char* _iadr) {
  2894.   static char iadr[HTS_URLMAXSIZE*2];
  2895.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  2896.  
  2897.   // sauter user:pass@ Θventuel
  2898.   strcpy(iadr,jump_identification(_iadr));
  2899.   // couper Θventuel :
  2900.   {
  2901.     char *a;
  2902.     if ( (a=strchr(iadr,':')) )
  2903.       *a='\0';
  2904.   }
  2905.  
  2906. #if HTS_WIN
  2907.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  2908. #else
  2909.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  2910. #endif
  2911.     return 1;
  2912.  
  2913.   while(_hts_lockdns(-1));  // attendre libΘration
  2914.   _hts_lockdns(1);          // locker
  2915.   while(1) {
  2916.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  2917.       _hts_lockdns(0);          // dΘlocker
  2918.       return 1;    // prΘsent!
  2919.     } else {    // on a pas encore trouvΘ
  2920.       if (cache->n!=NULL) { // chercher encore
  2921.         cache=cache->n;   // suivant!
  2922.       } else {
  2923.         _hts_lockdns(0);          // dΘlocker
  2924.         return 2;    // non prΘsent        
  2925.       }
  2926.     }    
  2927.   }
  2928. }
  2929.  
  2930. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  2931. t_hostent* hts_gethostbyname(char* _iadr) {
  2932.   static char iadr[HTS_URLMAXSIZE*2];
  2933.   static t_hostent host;
  2934.   static char adr[HTS_URLMAXSIZE*2]="";  // buffer adr pour host
  2935.   static char* he[2];
  2936.   static unsigned long inetaddr;
  2937.   //
  2938.   t_dnscache* cache=_hts_cache();  // adresse du cache
  2939.   t_hostent* hp;
  2940.  
  2941.   strcpy(iadr,jump_identification(_iadr));
  2942.   // couper Θventuel :
  2943.   {
  2944.     char *a;
  2945.     if ( (a=strchr(adr,':')) )
  2946.       *a='\0';
  2947.   }
  2948.  
  2949.   // effacer structure de retour, crΘer nouvelle
  2950.   bzero((char *)&host,sizeof(t_hostent));  
  2951.   host.h_addr_list=he;
  2952.   he[0]=adr;
  2953.   he[1]=NULL;  
  2954.   host.h_length=0;  
  2955.   cache->iadr[0]='*';
  2956.   cache->iadr[1]='\0';
  2957.   
  2958.   /* get IP from the dns cache */
  2959.   hp = _hts_ghbn(cache,iadr,&host);
  2960.   if (hp) {
  2961.     if (hp->h_length>0)
  2962.       return hp;
  2963.     else
  2964.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  2965.   } else {  // non prΘsent dans le cache dns, tester
  2966.     t_dnscache* c=cache;
  2967.     while(c->n) c=c->n;    // calculer queue
  2968.     
  2969. #if HTS_WIDE_DEBUG    
  2970.     DEBUG_W("gethostbyname\n");
  2971. #endif      
  2972. #if HDEBUG
  2973.     printf("gethostbyname (not in cache)\n");
  2974. #endif
  2975.     {
  2976. #if HTS_WIN
  2977.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  2978. #else
  2979.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  2980. #endif        
  2981. #if DEBUGDNS 
  2982.         printf("resolving (not cached) %s\n",iadr);
  2983. #endif
  2984.         hp=gethostbyname(iadr);  // calculer IP host
  2985.       } else {     // numΘrique, convertir sans passer par le dns
  2986.         host.h_addr=(char*) &inetaddr;
  2987.         host.h_length=4;
  2988.         hp=&host;
  2989.       }
  2990.     }
  2991. #if HTS_WIDE_DEBUG    
  2992.     DEBUG_W("gethostbyname done\n");
  2993. #endif
  2994.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  2995.     if (cache->n!=NULL) {
  2996.       strcpy(cache->n->iadr,iadr);
  2997.       if (hp!=NULL) {
  2998.         bcopy(hp->h_addr,cache->n->host_addr,hp->h_length);
  2999.         cache->n->host_length=hp->h_length;
  3000.       } else {
  3001.         cache->n->host_addr[0]='\0';
  3002.         cache->n->host_length=0;  // non existant dans le dns
  3003.       }
  3004.       cache->n->n=NULL;
  3005.       return hp;
  3006.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  3007.       return hp;
  3008.     }        
  3009.   }  // retour hp du cache
  3010. }
  3011.  
  3012. #else
  3013. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr) {
  3014.   t_hostent* retour;
  3015. #if HTS_WIDE_DEBUG    
  3016.   DEBUG_W("gethostbyname (2)\n");
  3017. #endif
  3018. #if DEBUGDNS 
  3019.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  3020. #endif
  3021.   retour=gethostbyname(jump_identification(iadr));
  3022. #if HTS_WIDE_DEBUG    
  3023.   DEBUG_W("gethostbyname (2) done\n");
  3024. #endif
  3025.   return retour;
  3026. }
  3027. #endif
  3028.  
  3029.  
  3030. // --- Tracage des mallocs() ---
  3031. #if HTS_TRACE_MALLOC
  3032. typedef struct _mlink {
  3033.   void* adr;
  3034.   int len;
  3035.   int id;
  3036.   struct _mlink* next;
  3037. } mlink;
  3038. mlink trmalloc = {NULL,0,0,NULL};
  3039. int trmalloc_id=0;
  3040.  
  3041. HTS_INLINE void* hts_malloc(size_t len,size_t len2) {
  3042.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  3043.   void*  r   = NULL;
  3044.   if (lnk) {
  3045.     if (len2)
  3046.       r = calloc(len,len2);
  3047.     else
  3048.       r = malloc(len);
  3049.     if (r) {
  3050.       lnk->adr=r;
  3051.       if (len2)
  3052.         lnk->len=len*len2;
  3053.       else
  3054.         lnk->len=len;
  3055.       lnk->id=trmalloc_id++;
  3056.       lnk->next=trmalloc.next;
  3057.       trmalloc.next=lnk;
  3058. #if MEMDEBUG
  3059.       //printf("malloc: %d\n",r);
  3060. #endif
  3061.     } else free(lnk);
  3062.   }
  3063.   return r;
  3064. }
  3065. HTS_INLINE void  hts_free(void* adr) {
  3066.   mlink* lnk = &trmalloc;
  3067.   if (!adr) {
  3068. #if MEMDEBUG
  3069.     printf("* unexpected free() error at %d\n",adr);
  3070. #endif
  3071.     return;
  3072.   }
  3073.   do {
  3074.     if (lnk->next->adr==adr) {
  3075.       mlink* blk_free=lnk->next;
  3076. #if 1
  3077.       lnk->next=lnk->next->next;
  3078.       free((void*) blk_free);
  3079. #else
  3080. #if MEMDEBUG
  3081.       if (blk_free->id==-1) {
  3082.         printf("* memory has already been freed: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3083.       }
  3084. #endif
  3085.       blk_free->id=-1;
  3086. #endif
  3087.       free(adr);
  3088. #if MEMDEBUG
  3089.       //printf("free: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3090. #endif
  3091.       return;
  3092.     }
  3093.     lnk=lnk->next;
  3094.   } while(lnk->next != NULL);
  3095. #if MEMDEBUG
  3096.   printf("* unexpected free() error at %d\n",adr);
  3097. #endif
  3098.   free(adr);
  3099. }
  3100. HTS_INLINE void* hts_realloc(void* adr,size_t len) {
  3101.   mlink* lnk = &trmalloc;
  3102.   do {
  3103.     if (lnk->next->adr==adr) {
  3104.       adr = realloc(adr,len);
  3105.       lnk->next->adr = adr;
  3106.       lnk->next->len = len;
  3107. #if MEMDEBUG
  3108.       //printf("realloc: %d (id=%d)\n",lnk->next->adr,lnk->next->id);
  3109. #endif
  3110.       return adr;
  3111.     }
  3112.     lnk=lnk->next;
  3113.   } while(lnk->next != NULL);
  3114. #if MEMDEBUG
  3115.   printf("* unexpected realloc() error at %d\n",adr);
  3116. #endif
  3117.   return realloc(adr,len);
  3118. }
  3119. // check the malloct() and calloct() trace stack
  3120. void  hts_freeall() {
  3121.   while(trmalloc.next) {
  3122. #if MEMDEBUG
  3123.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  3124. #endif
  3125.     if (trmalloc.next->id != -1) {
  3126.       freet(trmalloc.next->adr);
  3127.     }
  3128.   }
  3129. }
  3130. #endif
  3131.  
  3132.  
  3133. // -- divers //
  3134.  
  3135. // cut path and project name
  3136. // patch also initial path
  3137. void cut_path(char* fullpath,char* path,char* pname) {
  3138.   path[0]=pname[0]='\0';
  3139.   if (strnotempty(fullpath)) {
  3140.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  3141.       fullpath[strlen(fullpath)-1]='\0';
  3142.     if (strlen(fullpath)>1) {
  3143.       char* a;
  3144.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  3145.       a=fullpath+strlen(fullpath)-2;
  3146.       while( (*a!='/') && ((int) a > (int) fullpath)) a--;
  3147.       if (*a=='/') a++;
  3148.       strcpy(pname,a);
  3149.       strncat(path,fullpath,(int) a-(int) fullpath);
  3150.     }
  3151.   }
  3152. }
  3153.  
  3154.  
  3155.  
  3156. // -- Gestion protocole ftp --
  3157.  
  3158. #if HTS_WIN
  3159. int ftp_available() {
  3160.   return 1;
  3161. }
  3162. #else
  3163. int ftp_available() {
  3164.   return 1;   // ok!
  3165.   //return 0;   // SOUS UNIX, PROBLEMES
  3166. }
  3167. #endif
  3168.  
  3169.  
  3170. // Fin
  3171.  
  3172.